media: rename soc_camera I2C drivers
authorMauro Carvalho Chehab <mchehab+samsung@kernel.org>
Fri, 19 Oct 2018 11:33:02 +0000 (08:33 -0300)
committerMauro Carvalho Chehab <mchehab+samsung@kernel.org>
Fri, 19 Oct 2018 12:07:46 +0000 (08:07 -0400)
Those drivers are part of the legacy SoC camera framework.
They're being converted to not use it, but sometimes we're
keeping both legacy any new driver.

This time, for example, we have two drivers on media with
the same name: ov772x. That's bad.

So, in order to prevent that to happen, let's prepend the SoC
legacy drivers with soc_.

No functional changes.

Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
19 files changed:
drivers/media/i2c/soc_camera/Makefile
drivers/media/i2c/soc_camera/mt9m001.c [deleted file]
drivers/media/i2c/soc_camera/mt9t112.c [deleted file]
drivers/media/i2c/soc_camera/mt9v022.c [deleted file]
drivers/media/i2c/soc_camera/ov5642.c [deleted file]
drivers/media/i2c/soc_camera/ov772x.c [deleted file]
drivers/media/i2c/soc_camera/ov9640.c [deleted file]
drivers/media/i2c/soc_camera/ov9740.c [deleted file]
drivers/media/i2c/soc_camera/rj54n1cb0c.c [deleted file]
drivers/media/i2c/soc_camera/soc_mt9m001.c [new file with mode: 0644]
drivers/media/i2c/soc_camera/soc_mt9t112.c [new file with mode: 0644]
drivers/media/i2c/soc_camera/soc_mt9v022.c [new file with mode: 0644]
drivers/media/i2c/soc_camera/soc_ov5642.c [new file with mode: 0644]
drivers/media/i2c/soc_camera/soc_ov772x.c [new file with mode: 0644]
drivers/media/i2c/soc_camera/soc_ov9640.c [new file with mode: 0644]
drivers/media/i2c/soc_camera/soc_ov9740.c [new file with mode: 0644]
drivers/media/i2c/soc_camera/soc_rj54n1cb0c.c [new file with mode: 0644]
drivers/media/i2c/soc_camera/soc_tw9910.c [new file with mode: 0644]
drivers/media/i2c/soc_camera/tw9910.c [deleted file]

index 8c7770f..09ae483 100644 (file)
@@ -1,10 +1,10 @@
 # SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_SOC_CAMERA_MT9M001)       += mt9m001.o
-obj-$(CONFIG_SOC_CAMERA_MT9T112)       += mt9t112.o
-obj-$(CONFIG_SOC_CAMERA_MT9V022)       += mt9v022.o
-obj-$(CONFIG_SOC_CAMERA_OV5642)                += ov5642.o
-obj-$(CONFIG_SOC_CAMERA_OV772X)                += ov772x.o
-obj-$(CONFIG_SOC_CAMERA_OV9640)                += ov9640.o
-obj-$(CONFIG_SOC_CAMERA_OV9740)                += ov9740.o
-obj-$(CONFIG_SOC_CAMERA_RJ54N1)                += rj54n1cb0c.o
-obj-$(CONFIG_SOC_CAMERA_TW9910)                += tw9910.o
+obj-$(CONFIG_SOC_CAMERA_MT9M001)       += soc_mt9m001.o
+obj-$(CONFIG_SOC_CAMERA_MT9T112)       += soc_mt9t112.o
+obj-$(CONFIG_SOC_CAMERA_MT9V022)       += soc_mt9v022.o
+obj-$(CONFIG_SOC_CAMERA_OV5642)                += soc_ov5642.o
+obj-$(CONFIG_SOC_CAMERA_OV772X)                += soc_ov772x.o
+obj-$(CONFIG_SOC_CAMERA_OV9640)                += soc_ov9640.o
+obj-$(CONFIG_SOC_CAMERA_OV9740)                += soc_ov9740.o
+obj-$(CONFIG_SOC_CAMERA_RJ54N1)                += soc_rj54n1cb0c.o
+obj-$(CONFIG_SOC_CAMERA_TW9910)                += soc_tw9910.o
diff --git a/drivers/media/i2c/soc_camera/mt9m001.c b/drivers/media/i2c/soc_camera/mt9m001.c
deleted file mode 100644 (file)
index a1a85ff..0000000
+++ /dev/null
@@ -1,757 +0,0 @@
-/*
- * Driver for MT9M001 CMOS Image Sensor from Micron
- *
- * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
- *
- * 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.
- */
-
-#include <linux/videodev2.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/log2.h>
-#include <linux/module.h>
-
-#include <media/soc_camera.h>
-#include <media/drv-intf/soc_mediabus.h>
-#include <media/v4l2-clk.h>
-#include <media/v4l2-subdev.h>
-#include <media/v4l2-ctrls.h>
-
-/*
- * mt9m001 i2c address 0x5d
- * The platform has to define struct i2c_board_info objects and link to them
- * from struct soc_camera_host_desc
- */
-
-/* mt9m001 selected register addresses */
-#define MT9M001_CHIP_VERSION           0x00
-#define MT9M001_ROW_START              0x01
-#define MT9M001_COLUMN_START           0x02
-#define MT9M001_WINDOW_HEIGHT          0x03
-#define MT9M001_WINDOW_WIDTH           0x04
-#define MT9M001_HORIZONTAL_BLANKING    0x05
-#define MT9M001_VERTICAL_BLANKING      0x06
-#define MT9M001_OUTPUT_CONTROL         0x07
-#define MT9M001_SHUTTER_WIDTH          0x09
-#define MT9M001_FRAME_RESTART          0x0b
-#define MT9M001_SHUTTER_DELAY          0x0c
-#define MT9M001_RESET                  0x0d
-#define MT9M001_READ_OPTIONS1          0x1e
-#define MT9M001_READ_OPTIONS2          0x20
-#define MT9M001_GLOBAL_GAIN            0x35
-#define MT9M001_CHIP_ENABLE            0xF1
-
-#define MT9M001_MAX_WIDTH              1280
-#define MT9M001_MAX_HEIGHT             1024
-#define MT9M001_MIN_WIDTH              48
-#define MT9M001_MIN_HEIGHT             32
-#define MT9M001_COLUMN_SKIP            20
-#define MT9M001_ROW_SKIP               12
-
-/* MT9M001 has only one fixed colorspace per pixelcode */
-struct mt9m001_datafmt {
-       u32     code;
-       enum v4l2_colorspace            colorspace;
-};
-
-/* Find a data format by a pixel code in an array */
-static const struct mt9m001_datafmt *mt9m001_find_datafmt(
-       u32 code, const struct mt9m001_datafmt *fmt,
-       int n)
-{
-       int i;
-       for (i = 0; i < n; i++)
-               if (fmt[i].code == code)
-                       return fmt + i;
-
-       return NULL;
-}
-
-static const struct mt9m001_datafmt mt9m001_colour_fmts[] = {
-       /*
-        * Order important: first natively supported,
-        * second supported with a GPIO extender
-        */
-       {MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB},
-       {MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
-};
-
-static const struct mt9m001_datafmt mt9m001_monochrome_fmts[] = {
-       /* Order important - see above */
-       {MEDIA_BUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG},
-       {MEDIA_BUS_FMT_Y8_1X8, V4L2_COLORSPACE_JPEG},
-};
-
-struct mt9m001 {
-       struct v4l2_subdev subdev;
-       struct v4l2_ctrl_handler hdl;
-       struct {
-               /* exposure/auto-exposure cluster */
-               struct v4l2_ctrl *autoexposure;
-               struct v4l2_ctrl *exposure;
-       };
-       struct v4l2_rect rect;  /* Sensor window */
-       struct v4l2_clk *clk;
-       const struct mt9m001_datafmt *fmt;
-       const struct mt9m001_datafmt *fmts;
-       int num_fmts;
-       unsigned int total_h;
-       unsigned short y_skip_top;      /* Lines to skip at the top */
-};
-
-static struct mt9m001 *to_mt9m001(const struct i2c_client *client)
-{
-       return container_of(i2c_get_clientdata(client), struct mt9m001, subdev);
-}
-
-static int reg_read(struct i2c_client *client, const u8 reg)
-{
-       return i2c_smbus_read_word_swapped(client, reg);
-}
-
-static int reg_write(struct i2c_client *client, const u8 reg,
-                    const u16 data)
-{
-       return i2c_smbus_write_word_swapped(client, reg, data);
-}
-
-static int reg_set(struct i2c_client *client, const u8 reg,
-                  const u16 data)
-{
-       int ret;
-
-       ret = reg_read(client, reg);
-       if (ret < 0)
-               return ret;
-       return reg_write(client, reg, ret | data);
-}
-
-static int reg_clear(struct i2c_client *client, const u8 reg,
-                    const u16 data)
-{
-       int ret;
-
-       ret = reg_read(client, reg);
-       if (ret < 0)
-               return ret;
-       return reg_write(client, reg, ret & ~data);
-}
-
-static int mt9m001_init(struct i2c_client *client)
-{
-       int ret;
-
-       dev_dbg(&client->dev, "%s\n", __func__);
-
-       /*
-        * We don't know, whether platform provides reset, issue a soft reset
-        * too. This returns all registers to their default values.
-        */
-       ret = reg_write(client, MT9M001_RESET, 1);
-       if (!ret)
-               ret = reg_write(client, MT9M001_RESET, 0);
-
-       /* Disable chip, synchronous option update */
-       if (!ret)
-               ret = reg_write(client, MT9M001_OUTPUT_CONTROL, 0);
-
-       return ret;
-}
-
-static int mt9m001_s_stream(struct v4l2_subdev *sd, int enable)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       /* Switch to master "normal" mode or stop sensor readout */
-       if (reg_write(client, MT9M001_OUTPUT_CONTROL, enable ? 2 : 0) < 0)
-               return -EIO;
-       return 0;
-}
-
-static int mt9m001_set_selection(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_selection *sel)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9m001 *mt9m001 = to_mt9m001(client);
-       struct v4l2_rect rect = sel->r;
-       const u16 hblank = 9, vblank = 25;
-       int ret;
-
-       if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
-           sel->target != V4L2_SEL_TGT_CROP)
-               return -EINVAL;
-
-       if (mt9m001->fmts == mt9m001_colour_fmts)
-               /*
-                * Bayer format - even number of rows for simplicity,
-                * but let the user play with the top row.
-                */
-               rect.height = ALIGN(rect.height, 2);
-
-       /* Datasheet requirement: see register description */
-       rect.width = ALIGN(rect.width, 2);
-       rect.left = ALIGN(rect.left, 2);
-
-       soc_camera_limit_side(&rect.left, &rect.width,
-                    MT9M001_COLUMN_SKIP, MT9M001_MIN_WIDTH, MT9M001_MAX_WIDTH);
-
-       soc_camera_limit_side(&rect.top, &rect.height,
-                    MT9M001_ROW_SKIP, MT9M001_MIN_HEIGHT, MT9M001_MAX_HEIGHT);
-
-       mt9m001->total_h = rect.height + mt9m001->y_skip_top + vblank;
-
-       /* Blanking and start values - default... */
-       ret = reg_write(client, MT9M001_HORIZONTAL_BLANKING, hblank);
-       if (!ret)
-               ret = reg_write(client, MT9M001_VERTICAL_BLANKING, vblank);
-
-       /*
-        * The caller provides a supported format, as verified per
-        * call to .set_fmt(FORMAT_TRY).
-        */
-       if (!ret)
-               ret = reg_write(client, MT9M001_COLUMN_START, rect.left);
-       if (!ret)
-               ret = reg_write(client, MT9M001_ROW_START, rect.top);
-       if (!ret)
-               ret = reg_write(client, MT9M001_WINDOW_WIDTH, rect.width - 1);
-       if (!ret)
-               ret = reg_write(client, MT9M001_WINDOW_HEIGHT,
-                               rect.height + mt9m001->y_skip_top - 1);
-       if (!ret && v4l2_ctrl_g_ctrl(mt9m001->autoexposure) == V4L2_EXPOSURE_AUTO)
-               ret = reg_write(client, MT9M001_SHUTTER_WIDTH, mt9m001->total_h);
-
-       if (!ret)
-               mt9m001->rect = rect;
-
-       return ret;
-}
-
-static int mt9m001_get_selection(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_selection *sel)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9m001 *mt9m001 = to_mt9m001(client);
-
-       if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
-               return -EINVAL;
-
-       switch (sel->target) {
-       case V4L2_SEL_TGT_CROP_BOUNDS:
-               sel->r.left = MT9M001_COLUMN_SKIP;
-               sel->r.top = MT9M001_ROW_SKIP;
-               sel->r.width = MT9M001_MAX_WIDTH;
-               sel->r.height = MT9M001_MAX_HEIGHT;
-               return 0;
-       case V4L2_SEL_TGT_CROP:
-               sel->r = mt9m001->rect;
-               return 0;
-       default:
-               return -EINVAL;
-       }
-}
-
-static int mt9m001_get_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_format *format)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9m001 *mt9m001 = to_mt9m001(client);
-       struct v4l2_mbus_framefmt *mf = &format->format;
-
-       if (format->pad)
-               return -EINVAL;
-
-       mf->width       = mt9m001->rect.width;
-       mf->height      = mt9m001->rect.height;
-       mf->code        = mt9m001->fmt->code;
-       mf->colorspace  = mt9m001->fmt->colorspace;
-       mf->field       = V4L2_FIELD_NONE;
-
-       return 0;
-}
-
-static int mt9m001_s_fmt(struct v4l2_subdev *sd,
-                        const struct mt9m001_datafmt *fmt,
-                        struct v4l2_mbus_framefmt *mf)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9m001 *mt9m001 = to_mt9m001(client);
-       struct v4l2_subdev_selection sel = {
-               .which = V4L2_SUBDEV_FORMAT_ACTIVE,
-               .target = V4L2_SEL_TGT_CROP,
-               .r.left = mt9m001->rect.left,
-               .r.top = mt9m001->rect.top,
-               .r.width = mf->width,
-               .r.height = mf->height,
-       };
-       int ret;
-
-       /* No support for scaling so far, just crop. TODO: use skipping */
-       ret = mt9m001_set_selection(sd, NULL, &sel);
-       if (!ret) {
-               mf->width       = mt9m001->rect.width;
-               mf->height      = mt9m001->rect.height;
-               mt9m001->fmt    = fmt;
-               mf->colorspace  = fmt->colorspace;
-       }
-
-       return ret;
-}
-
-static int mt9m001_set_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_format *format)
-{
-       struct v4l2_mbus_framefmt *mf = &format->format;
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9m001 *mt9m001 = to_mt9m001(client);
-       const struct mt9m001_datafmt *fmt;
-
-       if (format->pad)
-               return -EINVAL;
-
-       v4l_bound_align_image(&mf->width, MT9M001_MIN_WIDTH,
-               MT9M001_MAX_WIDTH, 1,
-               &mf->height, MT9M001_MIN_HEIGHT + mt9m001->y_skip_top,
-               MT9M001_MAX_HEIGHT + mt9m001->y_skip_top, 0, 0);
-
-       if (mt9m001->fmts == mt9m001_colour_fmts)
-               mf->height = ALIGN(mf->height - 1, 2);
-
-       fmt = mt9m001_find_datafmt(mf->code, mt9m001->fmts,
-                                  mt9m001->num_fmts);
-       if (!fmt) {
-               fmt = mt9m001->fmt;
-               mf->code = fmt->code;
-       }
-
-       mf->colorspace  = fmt->colorspace;
-
-       if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
-               return mt9m001_s_fmt(sd, fmt, mf);
-       cfg->try_fmt = *mf;
-       return 0;
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int mt9m001_g_register(struct v4l2_subdev *sd,
-                             struct v4l2_dbg_register *reg)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (reg->reg > 0xff)
-               return -EINVAL;
-
-       reg->size = 2;
-       reg->val = reg_read(client, reg->reg);
-
-       if (reg->val > 0xffff)
-               return -EIO;
-
-       return 0;
-}
-
-static int mt9m001_s_register(struct v4l2_subdev *sd,
-                             const struct v4l2_dbg_register *reg)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (reg->reg > 0xff)
-               return -EINVAL;
-
-       if (reg_write(client, reg->reg, reg->val) < 0)
-               return -EIO;
-
-       return 0;
-}
-#endif
-
-static int mt9m001_s_power(struct v4l2_subdev *sd, int on)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
-       struct mt9m001 *mt9m001 = to_mt9m001(client);
-
-       return soc_camera_set_power(&client->dev, ssdd, mt9m001->clk, on);
-}
-
-static int mt9m001_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
-{
-       struct mt9m001 *mt9m001 = container_of(ctrl->handler,
-                                              struct mt9m001, hdl);
-       s32 min, max;
-
-       switch (ctrl->id) {
-       case V4L2_CID_EXPOSURE_AUTO:
-               min = mt9m001->exposure->minimum;
-               max = mt9m001->exposure->maximum;
-               mt9m001->exposure->val =
-                       (524 + (mt9m001->total_h - 1) * (max - min)) / 1048 + min;
-               break;
-       }
-       return 0;
-}
-
-static int mt9m001_s_ctrl(struct v4l2_ctrl *ctrl)
-{
-       struct mt9m001 *mt9m001 = container_of(ctrl->handler,
-                                              struct mt9m001, hdl);
-       struct v4l2_subdev *sd = &mt9m001->subdev;
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct v4l2_ctrl *exp = mt9m001->exposure;
-       int data;
-
-       switch (ctrl->id) {
-       case V4L2_CID_VFLIP:
-               if (ctrl->val)
-                       data = reg_set(client, MT9M001_READ_OPTIONS2, 0x8000);
-               else
-                       data = reg_clear(client, MT9M001_READ_OPTIONS2, 0x8000);
-               if (data < 0)
-                       return -EIO;
-               return 0;
-
-       case V4L2_CID_GAIN:
-               /* See Datasheet Table 7, Gain settings. */
-               if (ctrl->val <= ctrl->default_value) {
-                       /* Pack it into 0..1 step 0.125, register values 0..8 */
-                       unsigned long range = ctrl->default_value - ctrl->minimum;
-                       data = ((ctrl->val - (s32)ctrl->minimum) * 8 + range / 2) / range;
-
-                       dev_dbg(&client->dev, "Setting gain %d\n", data);
-                       data = reg_write(client, MT9M001_GLOBAL_GAIN, data);
-                       if (data < 0)
-                               return -EIO;
-               } else {
-                       /* Pack it into 1.125..15 variable step, register values 9..67 */
-                       /* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */
-                       unsigned long range = ctrl->maximum - ctrl->default_value - 1;
-                       unsigned long gain = ((ctrl->val - (s32)ctrl->default_value - 1) *
-                                              111 + range / 2) / range + 9;
-
-                       if (gain <= 32)
-                               data = gain;
-                       else if (gain <= 64)
-                               data = ((gain - 32) * 16 + 16) / 32 + 80;
-                       else
-                               data = ((gain - 64) * 7 + 28) / 56 + 96;
-
-                       dev_dbg(&client->dev, "Setting gain from %d to %d\n",
-                                reg_read(client, MT9M001_GLOBAL_GAIN), data);
-                       data = reg_write(client, MT9M001_GLOBAL_GAIN, data);
-                       if (data < 0)
-                               return -EIO;
-               }
-               return 0;
-
-       case V4L2_CID_EXPOSURE_AUTO:
-               if (ctrl->val == V4L2_EXPOSURE_MANUAL) {
-                       unsigned long range = exp->maximum - exp->minimum;
-                       unsigned long shutter = ((exp->val - (s32)exp->minimum) * 1048 +
-                                                range / 2) / range + 1;
-
-                       dev_dbg(&client->dev,
-                               "Setting shutter width from %d to %lu\n",
-                               reg_read(client, MT9M001_SHUTTER_WIDTH), shutter);
-                       if (reg_write(client, MT9M001_SHUTTER_WIDTH, shutter) < 0)
-                               return -EIO;
-               } else {
-                       const u16 vblank = 25;
-
-                       mt9m001->total_h = mt9m001->rect.height +
-                               mt9m001->y_skip_top + vblank;
-                       if (reg_write(client, MT9M001_SHUTTER_WIDTH, mt9m001->total_h) < 0)
-                               return -EIO;
-               }
-               return 0;
-       }
-       return -EINVAL;
-}
-
-/*
- * Interface active, can use i2c. If it fails, it can indeed mean, that
- * this wasn't our capture interface, so, we wait for the right one
- */
-static int mt9m001_video_probe(struct soc_camera_subdev_desc *ssdd,
-                              struct i2c_client *client)
-{
-       struct mt9m001 *mt9m001 = to_mt9m001(client);
-       s32 data;
-       unsigned long flags;
-       int ret;
-
-       ret = mt9m001_s_power(&mt9m001->subdev, 1);
-       if (ret < 0)
-               return ret;
-
-       /* Enable the chip */
-       data = reg_write(client, MT9M001_CHIP_ENABLE, 1);
-       dev_dbg(&client->dev, "write: %d\n", data);
-
-       /* Read out the chip version register */
-       data = reg_read(client, MT9M001_CHIP_VERSION);
-
-       /* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */
-       switch (data) {
-       case 0x8411:
-       case 0x8421:
-               mt9m001->fmts = mt9m001_colour_fmts;
-               break;
-       case 0x8431:
-               mt9m001->fmts = mt9m001_monochrome_fmts;
-               break;
-       default:
-               dev_err(&client->dev,
-                       "No MT9M001 chip detected, register read %x\n", data);
-               ret = -ENODEV;
-               goto done;
-       }
-
-       mt9m001->num_fmts = 0;
-
-       /*
-        * This is a 10bit sensor, so by default we only allow 10bit.
-        * The platform may support different bus widths due to
-        * different routing of the data lines.
-        */
-       if (ssdd->query_bus_param)
-               flags = ssdd->query_bus_param(ssdd);
-       else
-               flags = SOCAM_DATAWIDTH_10;
-
-       if (flags & SOCAM_DATAWIDTH_10)
-               mt9m001->num_fmts++;
-       else
-               mt9m001->fmts++;
-
-       if (flags & SOCAM_DATAWIDTH_8)
-               mt9m001->num_fmts++;
-
-       mt9m001->fmt = &mt9m001->fmts[0];
-
-       dev_info(&client->dev, "Detected a MT9M001 chip ID %x (%s)\n", data,
-                data == 0x8431 ? "C12STM" : "C12ST");
-
-       ret = mt9m001_init(client);
-       if (ret < 0) {
-               dev_err(&client->dev, "Failed to initialise the camera\n");
-               goto done;
-       }
-
-       /* mt9m001_init() has reset the chip, returning registers to defaults */
-       ret = v4l2_ctrl_handler_setup(&mt9m001->hdl);
-
-done:
-       mt9m001_s_power(&mt9m001->subdev, 0);
-       return ret;
-}
-
-static void mt9m001_video_remove(struct soc_camera_subdev_desc *ssdd)
-{
-       if (ssdd->free_bus)
-               ssdd->free_bus(ssdd);
-}
-
-static int mt9m001_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9m001 *mt9m001 = to_mt9m001(client);
-
-       *lines = mt9m001->y_skip_top;
-
-       return 0;
-}
-
-static const struct v4l2_ctrl_ops mt9m001_ctrl_ops = {
-       .g_volatile_ctrl = mt9m001_g_volatile_ctrl,
-       .s_ctrl = mt9m001_s_ctrl,
-};
-
-static const struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = {
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       .g_register     = mt9m001_g_register,
-       .s_register     = mt9m001_s_register,
-#endif
-       .s_power        = mt9m001_s_power,
-};
-
-static int mt9m001_enum_mbus_code(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_mbus_code_enum *code)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9m001 *mt9m001 = to_mt9m001(client);
-
-       if (code->pad || code->index >= mt9m001->num_fmts)
-               return -EINVAL;
-
-       code->code = mt9m001->fmts[code->index].code;
-       return 0;
-}
-
-static int mt9m001_g_mbus_config(struct v4l2_subdev *sd,
-                               struct v4l2_mbus_config *cfg)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
-
-       /* MT9M001 has all capture_format parameters fixed */
-       cfg->flags = V4L2_MBUS_PCLK_SAMPLE_FALLING |
-               V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH |
-               V4L2_MBUS_DATA_ACTIVE_HIGH | V4L2_MBUS_MASTER;
-       cfg->type = V4L2_MBUS_PARALLEL;
-       cfg->flags = soc_camera_apply_board_flags(ssdd, cfg);
-
-       return 0;
-}
-
-static int mt9m001_s_mbus_config(struct v4l2_subdev *sd,
-                               const struct v4l2_mbus_config *cfg)
-{
-       const struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
-       struct mt9m001 *mt9m001 = to_mt9m001(client);
-       unsigned int bps = soc_mbus_get_fmtdesc(mt9m001->fmt->code)->bits_per_sample;
-
-       if (ssdd->set_bus_param)
-               return ssdd->set_bus_param(ssdd, 1 << (bps - 1));
-
-       /*
-        * Without board specific bus width settings we only support the
-        * sensors native bus width
-        */
-       return bps == 10 ? 0 : -EINVAL;
-}
-
-static const struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = {
-       .s_stream       = mt9m001_s_stream,
-       .g_mbus_config  = mt9m001_g_mbus_config,
-       .s_mbus_config  = mt9m001_s_mbus_config,
-};
-
-static const struct v4l2_subdev_sensor_ops mt9m001_subdev_sensor_ops = {
-       .g_skip_top_lines       = mt9m001_g_skip_top_lines,
-};
-
-static const struct v4l2_subdev_pad_ops mt9m001_subdev_pad_ops = {
-       .enum_mbus_code = mt9m001_enum_mbus_code,
-       .get_selection  = mt9m001_get_selection,
-       .set_selection  = mt9m001_set_selection,
-       .get_fmt        = mt9m001_get_fmt,
-       .set_fmt        = mt9m001_set_fmt,
-};
-
-static const struct v4l2_subdev_ops mt9m001_subdev_ops = {
-       .core   = &mt9m001_subdev_core_ops,
-       .video  = &mt9m001_subdev_video_ops,
-       .sensor = &mt9m001_subdev_sensor_ops,
-       .pad    = &mt9m001_subdev_pad_ops,
-};
-
-static int mt9m001_probe(struct i2c_client *client,
-                        const struct i2c_device_id *did)
-{
-       struct mt9m001 *mt9m001;
-       struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
-       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
-       int ret;
-
-       if (!ssdd) {
-               dev_err(&client->dev, "MT9M001 driver needs platform data\n");
-               return -EINVAL;
-       }
-
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
-               dev_warn(&adapter->dev,
-                        "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
-               return -EIO;
-       }
-
-       mt9m001 = devm_kzalloc(&client->dev, sizeof(struct mt9m001), GFP_KERNEL);
-       if (!mt9m001)
-               return -ENOMEM;
-
-       v4l2_i2c_subdev_init(&mt9m001->subdev, client, &mt9m001_subdev_ops);
-       v4l2_ctrl_handler_init(&mt9m001->hdl, 4);
-       v4l2_ctrl_new_std(&mt9m001->hdl, &mt9m001_ctrl_ops,
-                       V4L2_CID_VFLIP, 0, 1, 1, 0);
-       v4l2_ctrl_new_std(&mt9m001->hdl, &mt9m001_ctrl_ops,
-                       V4L2_CID_GAIN, 0, 127, 1, 64);
-       mt9m001->exposure = v4l2_ctrl_new_std(&mt9m001->hdl, &mt9m001_ctrl_ops,
-                       V4L2_CID_EXPOSURE, 1, 255, 1, 255);
-       /*
-        * Simulated autoexposure. If enabled, we calculate shutter width
-        * ourselves in the driver based on vertical blanking and frame width
-        */
-       mt9m001->autoexposure = v4l2_ctrl_new_std_menu(&mt9m001->hdl,
-                       &mt9m001_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0,
-                       V4L2_EXPOSURE_AUTO);
-       mt9m001->subdev.ctrl_handler = &mt9m001->hdl;
-       if (mt9m001->hdl.error)
-               return mt9m001->hdl.error;
-
-       v4l2_ctrl_auto_cluster(2, &mt9m001->autoexposure,
-                                       V4L2_EXPOSURE_MANUAL, true);
-
-       /* Second stage probe - when a capture adapter is there */
-       mt9m001->y_skip_top     = 0;
-       mt9m001->rect.left      = MT9M001_COLUMN_SKIP;
-       mt9m001->rect.top       = MT9M001_ROW_SKIP;
-       mt9m001->rect.width     = MT9M001_MAX_WIDTH;
-       mt9m001->rect.height    = MT9M001_MAX_HEIGHT;
-
-       mt9m001->clk = v4l2_clk_get(&client->dev, "mclk");
-       if (IS_ERR(mt9m001->clk)) {
-               ret = PTR_ERR(mt9m001->clk);
-               goto eclkget;
-       }
-
-       ret = mt9m001_video_probe(ssdd, client);
-       if (ret) {
-               v4l2_clk_put(mt9m001->clk);
-eclkget:
-               v4l2_ctrl_handler_free(&mt9m001->hdl);
-       }
-
-       return ret;
-}
-
-static int mt9m001_remove(struct i2c_client *client)
-{
-       struct mt9m001 *mt9m001 = to_mt9m001(client);
-       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
-
-       v4l2_clk_put(mt9m001->clk);
-       v4l2_device_unregister_subdev(&mt9m001->subdev);
-       v4l2_ctrl_handler_free(&mt9m001->hdl);
-       mt9m001_video_remove(ssdd);
-
-       return 0;
-}
-
-static const struct i2c_device_id mt9m001_id[] = {
-       { "mt9m001", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, mt9m001_id);
-
-static struct i2c_driver mt9m001_i2c_driver = {
-       .driver = {
-               .name = "mt9m001",
-       },
-       .probe          = mt9m001_probe,
-       .remove         = mt9m001_remove,
-       .id_table       = mt9m001_id,
-};
-
-module_i2c_driver(mt9m001_i2c_driver);
-
-MODULE_DESCRIPTION("Micron MT9M001 Camera driver");
-MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/soc_camera/mt9t112.c b/drivers/media/i2c/soc_camera/mt9t112.c
deleted file mode 100644 (file)
index ea1ff27..0000000
+++ /dev/null
@@ -1,1157 +0,0 @@
-/*
- * mt9t112 Camera Driver
- *
- * Copyright (C) 2009 Renesas Solutions Corp.
- * Kuninori Morimoto <morimoto.kuninori@renesas.com>
- *
- * Based on ov772x driver, mt9m111 driver,
- *
- * Copyright (C) 2008 Kuninori Morimoto <morimoto.kuninori@renesas.com>
- * Copyright (C) 2008, Robert Jarzmik <robert.jarzmik@free.fr>
- * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
- * Copyright (C) 2008 Magnus Damm
- * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
- *
- * 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.
- */
-
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/v4l2-mediabus.h>
-#include <linux/videodev2.h>
-
-#include <media/i2c/mt9t112.h>
-#include <media/soc_camera.h>
-#include <media/v4l2-clk.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-image-sizes.h>
-
-/* you can check PLL/clock info */
-/* #define EXT_CLOCK 24000000 */
-
-/************************************************************************
-                       macro
-************************************************************************/
-/*
- * frame size
- */
-#define MAX_WIDTH   2048
-#define MAX_HEIGHT  1536
-
-/*
- * macro of read/write
- */
-#define ECHECKER(ret, x)               \
-       do {                            \
-               (ret) = (x);            \
-               if ((ret) < 0)          \
-                       return (ret);   \
-       } while (0)
-
-#define mt9t112_reg_write(ret, client, a, b) \
-       ECHECKER(ret, __mt9t112_reg_write(client, a, b))
-#define mt9t112_mcu_write(ret, client, a, b) \
-       ECHECKER(ret, __mt9t112_mcu_write(client, a, b))
-
-#define mt9t112_reg_mask_set(ret, client, a, b, c) \
-       ECHECKER(ret, __mt9t112_reg_mask_set(client, a, b, c))
-#define mt9t112_mcu_mask_set(ret, client, a, b, c) \
-       ECHECKER(ret, __mt9t112_mcu_mask_set(client, a, b, c))
-
-#define mt9t112_reg_read(ret, client, a) \
-       ECHECKER(ret, __mt9t112_reg_read(client, a))
-
-/*
- * Logical address
- */
-#define _VAR(id, offset, base) (base | (id & 0x1f) << 10 | (offset & 0x3ff))
-#define VAR(id, offset)  _VAR(id, offset, 0x0000)
-#define VAR8(id, offset) _VAR(id, offset, 0x8000)
-
-/************************************************************************
-                       struct
-************************************************************************/
-struct mt9t112_format {
-       u32 code;
-       enum v4l2_colorspace colorspace;
-       u16 fmt;
-       u16 order;
-};
-
-struct mt9t112_priv {
-       struct v4l2_subdev               subdev;
-       struct mt9t112_platform_data    *info;
-       struct i2c_client               *client;
-       struct v4l2_rect                 frame;
-       struct v4l2_clk                 *clk;
-       const struct mt9t112_format     *format;
-       int                              num_formats;
-       u32                              flags;
-/* for flags */
-#define INIT_DONE      (1 << 0)
-#define PCLK_RISING    (1 << 1)
-};
-
-/************************************************************************
-                       supported format
-************************************************************************/
-
-static const struct mt9t112_format mt9t112_cfmts[] = {
-       {
-               .code           = MEDIA_BUS_FMT_UYVY8_2X8,
-               .colorspace     = V4L2_COLORSPACE_SRGB,
-               .fmt            = 1,
-               .order          = 0,
-       }, {
-               .code           = MEDIA_BUS_FMT_VYUY8_2X8,
-               .colorspace     = V4L2_COLORSPACE_SRGB,
-               .fmt            = 1,
-               .order          = 1,
-       }, {
-               .code           = MEDIA_BUS_FMT_YUYV8_2X8,
-               .colorspace     = V4L2_COLORSPACE_SRGB,
-               .fmt            = 1,
-               .order          = 2,
-       }, {
-               .code           = MEDIA_BUS_FMT_YVYU8_2X8,
-               .colorspace     = V4L2_COLORSPACE_SRGB,
-               .fmt            = 1,
-               .order          = 3,
-       }, {
-               .code           = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE,
-               .colorspace     = V4L2_COLORSPACE_SRGB,
-               .fmt            = 8,
-               .order          = 2,
-       }, {
-               .code           = MEDIA_BUS_FMT_RGB565_2X8_LE,
-               .colorspace     = V4L2_COLORSPACE_SRGB,
-               .fmt            = 4,
-               .order          = 2,
-       },
-};
-
-/************************************************************************
-                       general function
-************************************************************************/
-static struct mt9t112_priv *to_mt9t112(const struct i2c_client *client)
-{
-       return container_of(i2c_get_clientdata(client),
-                           struct mt9t112_priv,
-                           subdev);
-}
-
-static int __mt9t112_reg_read(const struct i2c_client *client, u16 command)
-{
-       struct i2c_msg msg[2];
-       u8 buf[2];
-       int ret;
-
-       command = swab16(command);
-
-       msg[0].addr  = client->addr;
-       msg[0].flags = 0;
-       msg[0].len   = 2;
-       msg[0].buf   = (u8 *)&command;
-
-       msg[1].addr  = client->addr;
-       msg[1].flags = I2C_M_RD;
-       msg[1].len   = 2;
-       msg[1].buf   = buf;
-
-       /*
-        * if return value of this function is < 0,
-        * it mean error.
-        * else, under 16bit is valid data.
-        */
-       ret = i2c_transfer(client->adapter, msg, 2);
-       if (ret < 0)
-               return ret;
-
-       memcpy(&ret, buf, 2);
-       return swab16(ret);
-}
-
-static int __mt9t112_reg_write(const struct i2c_client *client,
-                              u16 command, u16 data)
-{
-       struct i2c_msg msg;
-       u8 buf[4];
-       int ret;
-
-       command = swab16(command);
-       data = swab16(data);
-
-       memcpy(buf + 0, &command, 2);
-       memcpy(buf + 2, &data,    2);
-
-       msg.addr  = client->addr;
-       msg.flags = 0;
-       msg.len   = 4;
-       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;
-}
-
-static int __mt9t112_reg_mask_set(const struct i2c_client *client,
-                                 u16  command,
-                                 u16  mask,
-                                 u16  set)
-{
-       int val = __mt9t112_reg_read(client, command);
-       if (val < 0)
-               return val;
-
-       val &= ~mask;
-       val |= set & mask;
-
-       return __mt9t112_reg_write(client, command, val);
-}
-
-/* mcu access */
-static int __mt9t112_mcu_read(const struct i2c_client *client, u16 command)
-{
-       int ret;
-
-       ret = __mt9t112_reg_write(client, 0x098E, command);
-       if (ret < 0)
-               return ret;
-
-       return __mt9t112_reg_read(client, 0x0990);
-}
-
-static int __mt9t112_mcu_write(const struct i2c_client *client,
-                              u16 command, u16 data)
-{
-       int ret;
-
-       ret = __mt9t112_reg_write(client, 0x098E, command);
-       if (ret < 0)
-               return ret;
-
-       return __mt9t112_reg_write(client, 0x0990, data);
-}
-
-static int __mt9t112_mcu_mask_set(const struct i2c_client *client,
-                                 u16  command,
-                                 u16  mask,
-                                 u16  set)
-{
-       int val = __mt9t112_mcu_read(client, command);
-       if (val < 0)
-               return val;
-
-       val &= ~mask;
-       val |= set & mask;
-
-       return __mt9t112_mcu_write(client, command, val);
-}
-
-static int mt9t112_reset(const struct i2c_client *client)
-{
-       int ret;
-
-       mt9t112_reg_mask_set(ret, client, 0x001a, 0x0001, 0x0001);
-       msleep(1);
-       mt9t112_reg_mask_set(ret, client, 0x001a, 0x0001, 0x0000);
-
-       return ret;
-}
-
-#ifndef EXT_CLOCK
-#define CLOCK_INFO(a, b)
-#else
-#define CLOCK_INFO(a, b) mt9t112_clock_info(a, b)
-static int mt9t112_clock_info(const struct i2c_client *client, u32 ext)
-{
-       int m, n, p1, p2, p3, p4, p5, p6, p7;
-       u32 vco, clk;
-       char *enable;
-
-       ext /= 1000; /* kbyte order */
-
-       mt9t112_reg_read(n, client, 0x0012);
-       p1 = n & 0x000f;
-       n = n >> 4;
-       p2 = n & 0x000f;
-       n = n >> 4;
-       p3 = n & 0x000f;
-
-       mt9t112_reg_read(n, client, 0x002a);
-       p4 = n & 0x000f;
-       n = n >> 4;
-       p5 = n & 0x000f;
-       n = n >> 4;
-       p6 = n & 0x000f;
-
-       mt9t112_reg_read(n, client, 0x002c);
-       p7 = n & 0x000f;
-
-       mt9t112_reg_read(n, client, 0x0010);
-       m = n & 0x00ff;
-       n = (n >> 8) & 0x003f;
-
-       enable = ((6000 > ext) || (54000 < ext)) ? "X" : "";
-       dev_dbg(&client->dev, "EXTCLK          : %10u K %s\n", ext, enable);
-
-       vco = 2 * m * ext / (n+1);
-       enable = ((384000 > vco) || (768000 < vco)) ? "X" : "";
-       dev_dbg(&client->dev, "VCO             : %10u K %s\n", vco, enable);
-
-       clk = vco / (p1+1) / (p2+1);
-       enable = (96000 < clk) ? "X" : "";
-       dev_dbg(&client->dev, "PIXCLK          : %10u K %s\n", clk, enable);
-
-       clk = vco / (p3+1);
-       enable = (768000 < clk) ? "X" : "";
-       dev_dbg(&client->dev, "MIPICLK         : %10u K %s\n", clk, enable);
-
-       clk = vco / (p6+1);
-       enable = (96000 < clk) ? "X" : "";
-       dev_dbg(&client->dev, "MCU CLK         : %10u K %s\n", clk, enable);
-
-       clk = vco / (p5+1);
-       enable = (54000 < clk) ? "X" : "";
-       dev_dbg(&client->dev, "SOC CLK         : %10u K %s\n", clk, enable);
-
-       clk = vco / (p4+1);
-       enable = (70000 < clk) ? "X" : "";
-       dev_dbg(&client->dev, "Sensor CLK      : %10u K %s\n", clk, enable);
-
-       clk = vco / (p7+1);
-       dev_dbg(&client->dev, "External sensor : %10u K\n", clk);
-
-       clk = ext / (n+1);
-       enable = ((2000 > clk) || (24000 < clk)) ? "X" : "";
-       dev_dbg(&client->dev, "PFD             : %10u K %s\n", clk, enable);
-
-       return 0;
-}
-#endif
-
-static void mt9t112_frame_check(u32 *width, u32 *height, u32 *left, u32 *top)
-{
-       soc_camera_limit_side(left, width, 0, 0, MAX_WIDTH);
-       soc_camera_limit_side(top, height, 0, 0, MAX_HEIGHT);
-}
-
-static int mt9t112_set_a_frame_size(const struct i2c_client *client,
-                                  u16 width,
-                                  u16 height)
-{
-       int ret;
-       u16 wstart = (MAX_WIDTH - width) / 2;
-       u16 hstart = (MAX_HEIGHT - height) / 2;
-
-       /* (Context A) Image Width/Height */
-       mt9t112_mcu_write(ret, client, VAR(26, 0), width);
-       mt9t112_mcu_write(ret, client, VAR(26, 2), height);
-
-       /* (Context A) Output Width/Height */
-       mt9t112_mcu_write(ret, client, VAR(18, 43), 8 + width);
-       mt9t112_mcu_write(ret, client, VAR(18, 45), 8 + height);
-
-       /* (Context A) Start Row/Column */
-       mt9t112_mcu_write(ret, client, VAR(18, 2), 4 + hstart);
-       mt9t112_mcu_write(ret, client, VAR(18, 4), 4 + wstart);
-
-       /* (Context A) End Row/Column */
-       mt9t112_mcu_write(ret, client, VAR(18, 6), 11 + height + hstart);
-       mt9t112_mcu_write(ret, client, VAR(18, 8), 11 + width  + wstart);
-
-       mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06);
-
-       return ret;
-}
-
-static int mt9t112_set_pll_dividers(const struct i2c_client *client,
-                                   u8 m, u8 n,
-                                   u8 p1, u8 p2, u8 p3,
-                                   u8 p4, u8 p5, u8 p6,
-                                   u8 p7)
-{
-       int ret;
-       u16 val;
-
-       /* N/M */
-       val = (n << 8) |
-             (m << 0);
-       mt9t112_reg_mask_set(ret, client, 0x0010, 0x3fff, val);
-
-       /* P1/P2/P3 */
-       val = ((p3 & 0x0F) << 8) |
-             ((p2 & 0x0F) << 4) |
-             ((p1 & 0x0F) << 0);
-       mt9t112_reg_mask_set(ret, client, 0x0012, 0x0fff, val);
-
-       /* P4/P5/P6 */
-       val = (0x7         << 12) |
-             ((p6 & 0x0F) <<  8) |
-             ((p5 & 0x0F) <<  4) |
-             ((p4 & 0x0F) <<  0);
-       mt9t112_reg_mask_set(ret, client, 0x002A, 0x7fff, val);
-
-       /* P7 */
-       val = (0x1         << 12) |
-             ((p7 & 0x0F) <<  0);
-       mt9t112_reg_mask_set(ret, client, 0x002C, 0x100f, val);
-
-       return ret;
-}
-
-static int mt9t112_init_pll(const struct i2c_client *client)
-{
-       struct mt9t112_priv *priv = to_mt9t112(client);
-       int data, i, ret;
-
-       mt9t112_reg_mask_set(ret, client, 0x0014, 0x003, 0x0001);
-
-       /* PLL control: BYPASS PLL = 8517 */
-       mt9t112_reg_write(ret, client, 0x0014, 0x2145);
-
-       /* Replace these registers when new timing parameters are generated */
-       mt9t112_set_pll_dividers(client,
-                                priv->info->divider.m,
-                                priv->info->divider.n,
-                                priv->info->divider.p1,
-                                priv->info->divider.p2,
-                                priv->info->divider.p3,
-                                priv->info->divider.p4,
-                                priv->info->divider.p5,
-                                priv->info->divider.p6,
-                                priv->info->divider.p7);
-
-       /*
-        * TEST_BYPASS  on
-        * PLL_ENABLE   on
-        * SEL_LOCK_DET on
-        * TEST_BYPASS  off
-        */
-       mt9t112_reg_write(ret, client, 0x0014, 0x2525);
-       mt9t112_reg_write(ret, client, 0x0014, 0x2527);
-       mt9t112_reg_write(ret, client, 0x0014, 0x3427);
-       mt9t112_reg_write(ret, client, 0x0014, 0x3027);
-
-       mdelay(10);
-
-       /*
-        * PLL_BYPASS off
-        * Reference clock count
-        * I2C Master Clock Divider
-        */
-       mt9t112_reg_write(ret, client, 0x0014, 0x3046);
-       mt9t112_reg_write(ret, client, 0x0016, 0x0400); /* JPEG initialization workaround */
-       mt9t112_reg_write(ret, client, 0x0022, 0x0190);
-       mt9t112_reg_write(ret, client, 0x3B84, 0x0212);
-
-       /* External sensor clock is PLL bypass */
-       mt9t112_reg_write(ret, client, 0x002E, 0x0500);
-
-       mt9t112_reg_mask_set(ret, client, 0x0018, 0x0002, 0x0002);
-       mt9t112_reg_mask_set(ret, client, 0x3B82, 0x0004, 0x0004);
-
-       /* MCU disabled */
-       mt9t112_reg_mask_set(ret, client, 0x0018, 0x0004, 0x0004);
-
-       /* out of standby */
-       mt9t112_reg_mask_set(ret, client, 0x0018, 0x0001, 0);
-
-       mdelay(50);
-
-       /*
-        * Standby Workaround
-        * Disable Secondary I2C Pads
-        */
-       mt9t112_reg_write(ret, client, 0x0614, 0x0001);
-       mdelay(1);
-       mt9t112_reg_write(ret, client, 0x0614, 0x0001);
-       mdelay(1);
-       mt9t112_reg_write(ret, client, 0x0614, 0x0001);
-       mdelay(1);
-       mt9t112_reg_write(ret, client, 0x0614, 0x0001);
-       mdelay(1);
-       mt9t112_reg_write(ret, client, 0x0614, 0x0001);
-       mdelay(1);
-       mt9t112_reg_write(ret, client, 0x0614, 0x0001);
-       mdelay(1);
-
-       /* poll to verify out of standby. Must Poll this bit */
-       for (i = 0; i < 100; i++) {
-               mt9t112_reg_read(data, client, 0x0018);
-               if (!(0x4000 & data))
-                       break;
-
-               mdelay(10);
-       }
-
-       return ret;
-}
-
-static int mt9t112_init_setting(const struct i2c_client *client)
-{
-
-       int ret;
-
-       /* Adaptive Output Clock (A) */
-       mt9t112_mcu_mask_set(ret, client, VAR(26, 160), 0x0040, 0x0000);
-
-       /* Read Mode (A) */
-       mt9t112_mcu_write(ret, client, VAR(18, 12), 0x0024);
-
-       /* Fine Correction (A) */
-       mt9t112_mcu_write(ret, client, VAR(18, 15), 0x00CC);
-
-       /* Fine IT Min (A) */
-       mt9t112_mcu_write(ret, client, VAR(18, 17), 0x01f1);
-
-       /* Fine IT Max Margin (A) */
-       mt9t112_mcu_write(ret, client, VAR(18, 19), 0x00fF);
-
-       /* Base Frame Lines (A) */
-       mt9t112_mcu_write(ret, client, VAR(18, 29), 0x032D);
-
-       /* Min Line Length (A) */
-       mt9t112_mcu_write(ret, client, VAR(18, 31), 0x073a);
-
-       /* Line Length (A) */
-       mt9t112_mcu_write(ret, client, VAR(18, 37), 0x07d0);
-
-       /* Adaptive Output Clock (B) */
-       mt9t112_mcu_mask_set(ret, client, VAR(27, 160), 0x0040, 0x0000);
-
-       /* Row Start (B) */
-       mt9t112_mcu_write(ret, client, VAR(18, 74), 0x004);
-
-       /* Column Start (B) */
-       mt9t112_mcu_write(ret, client, VAR(18, 76), 0x004);
-
-       /* Row End (B) */
-       mt9t112_mcu_write(ret, client, VAR(18, 78), 0x60B);
-
-       /* Column End (B) */
-       mt9t112_mcu_write(ret, client, VAR(18, 80), 0x80B);
-
-       /* Fine Correction (B) */
-       mt9t112_mcu_write(ret, client, VAR(18, 87), 0x008C);
-
-       /* Fine IT Min (B) */
-       mt9t112_mcu_write(ret, client, VAR(18, 89), 0x01F1);
-
-       /* Fine IT Max Margin (B) */
-       mt9t112_mcu_write(ret, client, VAR(18, 91), 0x00FF);
-
-       /* Base Frame Lines (B) */
-       mt9t112_mcu_write(ret, client, VAR(18, 101), 0x0668);
-
-       /* Min Line Length (B) */
-       mt9t112_mcu_write(ret, client, VAR(18, 103), 0x0AF0);
-
-       /* Line Length (B) */
-       mt9t112_mcu_write(ret, client, VAR(18, 109), 0x0AF0);
-
-       /*
-        * Flicker Dectection registers
-        * This section should be replaced whenever new Timing file is generated
-        * All the following registers need to be replaced
-        * Following registers are generated from Register Wizard but user can
-        * modify them. For detail see auto flicker detection tuning
-        */
-
-       /* FD_FDPERIOD_SELECT */
-       mt9t112_mcu_write(ret, client, VAR8(8, 5), 0x01);
-
-       /* PRI_B_CONFIG_FD_ALGO_RUN */
-       mt9t112_mcu_write(ret, client, VAR(27, 17), 0x0003);
-
-       /* PRI_A_CONFIG_FD_ALGO_RUN */
-       mt9t112_mcu_write(ret, client, VAR(26, 17), 0x0003);
-
-       /*
-        * AFD range detection tuning registers
-        */
-
-       /* search_f1_50 */
-       mt9t112_mcu_write(ret, client, VAR8(18, 165), 0x25);
-
-       /* search_f2_50 */
-       mt9t112_mcu_write(ret, client, VAR8(18, 166), 0x28);
-
-       /* search_f1_60 */
-       mt9t112_mcu_write(ret, client, VAR8(18, 167), 0x2C);
-
-       /* search_f2_60 */
-       mt9t112_mcu_write(ret, client, VAR8(18, 168), 0x2F);
-
-       /* period_50Hz (A) */
-       mt9t112_mcu_write(ret, client, VAR8(18, 68), 0xBA);
-
-       /* secret register by aptina */
-       /* period_50Hz (A MSB) */
-       mt9t112_mcu_write(ret, client, VAR8(18, 303), 0x00);
-
-       /* period_60Hz (A) */
-       mt9t112_mcu_write(ret, client, VAR8(18, 69), 0x9B);
-
-       /* secret register by aptina */
-       /* period_60Hz (A MSB) */
-       mt9t112_mcu_write(ret, client, VAR8(18, 301), 0x00);
-
-       /* period_50Hz (B) */
-       mt9t112_mcu_write(ret, client, VAR8(18, 140), 0x82);
-
-       /* secret register by aptina */
-       /* period_50Hz (B) MSB */
-       mt9t112_mcu_write(ret, client, VAR8(18, 304), 0x00);
-
-       /* period_60Hz (B) */
-       mt9t112_mcu_write(ret, client, VAR8(18, 141), 0x6D);
-
-       /* secret register by aptina */
-       /* period_60Hz (B) MSB */
-       mt9t112_mcu_write(ret, client, VAR8(18, 302), 0x00);
-
-       /* FD Mode */
-       mt9t112_mcu_write(ret, client, VAR8(8, 2), 0x10);
-
-       /* Stat_min */
-       mt9t112_mcu_write(ret, client, VAR8(8, 9), 0x02);
-
-       /* Stat_max */
-       mt9t112_mcu_write(ret, client, VAR8(8, 10), 0x03);
-
-       /* Min_amplitude */
-       mt9t112_mcu_write(ret, client, VAR8(8, 12), 0x0A);
-
-       /* RX FIFO Watermark (A) */
-       mt9t112_mcu_write(ret, client, VAR(18, 70), 0x0014);
-
-       /* RX FIFO Watermark (B) */
-       mt9t112_mcu_write(ret, client, VAR(18, 142), 0x0014);
-
-       /* MCLK: 16MHz
-        * PCLK: 73MHz
-        * CorePixCLK: 36.5 MHz
-        */
-       mt9t112_mcu_write(ret, client, VAR8(18, 0x0044), 133);
-       mt9t112_mcu_write(ret, client, VAR8(18, 0x0045), 110);
-       mt9t112_mcu_write(ret, client, VAR8(18, 0x008c), 130);
-       mt9t112_mcu_write(ret, client, VAR8(18, 0x008d), 108);
-
-       mt9t112_mcu_write(ret, client, VAR8(18, 0x00A5), 27);
-       mt9t112_mcu_write(ret, client, VAR8(18, 0x00a6), 30);
-       mt9t112_mcu_write(ret, client, VAR8(18, 0x00a7), 32);
-       mt9t112_mcu_write(ret, client, VAR8(18, 0x00a8), 35);
-
-       return ret;
-}
-
-static int mt9t112_auto_focus_setting(const struct i2c_client *client)
-{
-       int ret;
-
-       mt9t112_mcu_write(ret, client, VAR(12, 13),     0x000F);
-       mt9t112_mcu_write(ret, client, VAR(12, 23),     0x0F0F);
-       mt9t112_mcu_write(ret, client, VAR8(1, 0),      0x06);
-
-       mt9t112_reg_write(ret, client, 0x0614, 0x0000);
-
-       mt9t112_mcu_write(ret, client, VAR8(1, 0),      0x05);
-       mt9t112_mcu_write(ret, client, VAR8(12, 2),     0x02);
-       mt9t112_mcu_write(ret, client, VAR(12, 3),      0x0002);
-       mt9t112_mcu_write(ret, client, VAR(17, 3),      0x8001);
-       mt9t112_mcu_write(ret, client, VAR(17, 11),     0x0025);
-       mt9t112_mcu_write(ret, client, VAR(17, 13),     0x0193);
-       mt9t112_mcu_write(ret, client, VAR8(17, 33),    0x18);
-       mt9t112_mcu_write(ret, client, VAR8(1, 0),      0x05);
-
-       return ret;
-}
-
-static int mt9t112_auto_focus_trigger(const struct i2c_client *client)
-{
-       int ret;
-
-       mt9t112_mcu_write(ret, client, VAR8(12, 25), 0x01);
-
-       return ret;
-}
-
-static int mt9t112_init_camera(const struct i2c_client *client)
-{
-       int ret;
-
-       ECHECKER(ret, mt9t112_reset(client));
-
-       ECHECKER(ret, mt9t112_init_pll(client));
-
-       ECHECKER(ret, mt9t112_init_setting(client));
-
-       ECHECKER(ret, mt9t112_auto_focus_setting(client));
-
-       mt9t112_reg_mask_set(ret, client, 0x0018, 0x0004, 0);
-
-       /* Analog setting B */
-       mt9t112_reg_write(ret, client, 0x3084, 0x2409);
-       mt9t112_reg_write(ret, client, 0x3092, 0x0A49);
-       mt9t112_reg_write(ret, client, 0x3094, 0x4949);
-       mt9t112_reg_write(ret, client, 0x3096, 0x4950);
-
-       /*
-        * Disable adaptive clock
-        * PRI_A_CONFIG_JPEG_OB_TX_CONTROL_VAR
-        * PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR
-        */
-       mt9t112_mcu_write(ret, client, VAR(26, 160), 0x0A2E);
-       mt9t112_mcu_write(ret, client, VAR(27, 160), 0x0A2E);
-
-       /* Configure STatus in Status_before_length Format and enable header */
-       /* PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR */
-       mt9t112_mcu_write(ret, client, VAR(27, 144), 0x0CB4);
-
-       /* Enable JPEG in context B */
-       /* PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR */
-       mt9t112_mcu_write(ret, client, VAR8(27, 142), 0x01);
-
-       /* Disable Dac_TXLO */
-       mt9t112_reg_write(ret, client, 0x316C, 0x350F);
-
-       /* Set max slew rates */
-       mt9t112_reg_write(ret, client, 0x1E, 0x777);
-
-       return ret;
-}
-
-/************************************************************************
-                       v4l2_subdev_core_ops
-************************************************************************/
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int mt9t112_g_register(struct v4l2_subdev *sd,
-                             struct v4l2_dbg_register *reg)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       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,
-                             const struct v4l2_dbg_register *reg)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret;
-
-       mt9t112_reg_write(ret, client, reg->reg, reg->val);
-
-       return ret;
-}
-#endif
-
-static int mt9t112_s_power(struct v4l2_subdev *sd, int on)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
-       struct mt9t112_priv *priv = to_mt9t112(client);
-
-       return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
-}
-
-static const struct v4l2_subdev_core_ops mt9t112_subdev_core_ops = {
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       .g_register     = mt9t112_g_register,
-       .s_register     = mt9t112_s_register,
-#endif
-       .s_power        = mt9t112_s_power,
-};
-
-
-/************************************************************************
-                       v4l2_subdev_video_ops
-************************************************************************/
-static int mt9t112_s_stream(struct v4l2_subdev *sd, int enable)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       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 = PCLK_RISING & priv->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 mt9t112_priv *priv,
-                             const struct v4l2_rect *rect,
-                             u32 code)
-{
-       int i;
-
-       /*
-        * get color format
-        */
-       for (i = 0; i < priv->num_formats; i++)
-               if (mt9t112_cfmts[i].code == code)
-                       break;
-
-       if (i == priv->num_formats)
-               return -EINVAL;
-
-       priv->frame  = *rect;
-
-       /*
-        * frame size check
-        */
-       mt9t112_frame_check(&priv->frame.width, &priv->frame.height,
-                           &priv->frame.left, &priv->frame.top);
-
-       priv->format = mt9t112_cfmts + i;
-
-       return 0;
-}
-
-static int mt9t112_get_selection(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_selection *sel)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9t112_priv *priv = to_mt9t112(client);
-
-       if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
-               return -EINVAL;
-
-       switch (sel->target) {
-       case V4L2_SEL_TGT_CROP_BOUNDS:
-               sel->r.left = 0;
-               sel->r.top = 0;
-               sel->r.width = MAX_WIDTH;
-               sel->r.height = MAX_HEIGHT;
-               return 0;
-       case V4L2_SEL_TGT_CROP:
-               sel->r = priv->frame;
-               return 0;
-       default:
-               return -EINVAL;
-       }
-}
-
-static int mt9t112_set_selection(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_selection *sel)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9t112_priv *priv = to_mt9t112(client);
-       const struct v4l2_rect *rect = &sel->r;
-
-       if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
-           sel->target != V4L2_SEL_TGT_CROP)
-               return -EINVAL;
-
-       return mt9t112_set_params(priv, rect, priv->format->code);
-}
-
-static int mt9t112_get_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_format *format)
-{
-       struct v4l2_mbus_framefmt *mf = &format->format;
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9t112_priv *priv = to_mt9t112(client);
-
-       if (format->pad)
-               return -EINVAL;
-
-       mf->width       = priv->frame.width;
-       mf->height      = priv->frame.height;
-       mf->colorspace  = priv->format->colorspace;
-       mf->code        = priv->format->code;
-       mf->field       = V4L2_FIELD_NONE;
-
-       return 0;
-}
-
-static int mt9t112_s_fmt(struct v4l2_subdev *sd,
-                        struct v4l2_mbus_framefmt *mf)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9t112_priv *priv = to_mt9t112(client);
-       struct v4l2_rect rect = {
-               .width = mf->width,
-               .height = mf->height,
-               .left = priv->frame.left,
-               .top = priv->frame.top,
-       };
-       int ret;
-
-       ret = mt9t112_set_params(priv, &rect, mf->code);
-
-       if (!ret)
-               mf->colorspace = priv->format->colorspace;
-
-       return ret;
-}
-
-static int mt9t112_set_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_format *format)
-{
-       struct v4l2_mbus_framefmt *mf = &format->format;
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9t112_priv *priv = to_mt9t112(client);
-       unsigned int top, left;
-       int i;
-
-       if (format->pad)
-               return -EINVAL;
-
-       for (i = 0; i < priv->num_formats; i++)
-               if (mt9t112_cfmts[i].code == mf->code)
-                       break;
-
-       if (i == priv->num_formats) {
-               mf->code = MEDIA_BUS_FMT_UYVY8_2X8;
-               mf->colorspace = V4L2_COLORSPACE_JPEG;
-       } else {
-               mf->colorspace  = mt9t112_cfmts[i].colorspace;
-       }
-
-       mt9t112_frame_check(&mf->width, &mf->height, &left, &top);
-
-       mf->field = V4L2_FIELD_NONE;
-
-       if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
-               return mt9t112_s_fmt(sd, mf);
-       cfg->try_fmt = *mf;
-       return 0;
-}
-
-static int mt9t112_enum_mbus_code(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_mbus_code_enum *code)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9t112_priv *priv = to_mt9t112(client);
-
-       if (code->pad || code->index >= priv->num_formats)
-               return -EINVAL;
-
-       code->code = mt9t112_cfmts[code->index].code;
-
-       return 0;
-}
-
-static int mt9t112_g_mbus_config(struct v4l2_subdev *sd,
-                                struct v4l2_mbus_config *cfg)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
-
-       cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_VSYNC_ACTIVE_HIGH |
-               V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_HIGH |
-               V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING;
-       cfg->type = V4L2_MBUS_PARALLEL;
-       cfg->flags = soc_camera_apply_board_flags(ssdd, cfg);
-
-       return 0;
-}
-
-static int mt9t112_s_mbus_config(struct v4l2_subdev *sd,
-                                const struct v4l2_mbus_config *cfg)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
-       struct mt9t112_priv *priv = to_mt9t112(client);
-
-       if (soc_camera_apply_board_flags(ssdd, cfg) & V4L2_MBUS_PCLK_SAMPLE_RISING)
-               priv->flags |= PCLK_RISING;
-
-       return 0;
-}
-
-static const struct v4l2_subdev_video_ops mt9t112_subdev_video_ops = {
-       .s_stream       = mt9t112_s_stream,
-       .g_mbus_config  = mt9t112_g_mbus_config,
-       .s_mbus_config  = mt9t112_s_mbus_config,
-};
-
-static const struct v4l2_subdev_pad_ops mt9t112_subdev_pad_ops = {
-       .enum_mbus_code = mt9t112_enum_mbus_code,
-       .get_selection  = mt9t112_get_selection,
-       .set_selection  = mt9t112_set_selection,
-       .get_fmt        = mt9t112_get_fmt,
-       .set_fmt        = mt9t112_set_fmt,
-};
-
-/************************************************************************
-                       i2c driver
-************************************************************************/
-static const struct v4l2_subdev_ops mt9t112_subdev_ops = {
-       .core   = &mt9t112_subdev_core_ops,
-       .video  = &mt9t112_subdev_video_ops,
-       .pad    = &mt9t112_subdev_pad_ops,
-};
-
-static int mt9t112_camera_probe(struct i2c_client *client)
-{
-       struct mt9t112_priv *priv = to_mt9t112(client);
-       const char          *devname;
-       int                  chipid;
-       int                  ret;
-
-       ret = mt9t112_s_power(&priv->subdev, 1);
-       if (ret < 0)
-               return ret;
-
-       /*
-        * check and show chip ID
-        */
-       mt9t112_reg_read(chipid, client, 0x0000);
-
-       switch (chipid) {
-       case 0x2680:
-               devname = "mt9t111";
-               priv->num_formats = 1;
-               break;
-       case 0x2682:
-               devname = "mt9t112";
-               priv->num_formats = ARRAY_SIZE(mt9t112_cfmts);
-               break;
-       default:
-               dev_err(&client->dev, "Product ID error %04x\n", chipid);
-               ret = -ENODEV;
-               goto done;
-       }
-
-       dev_info(&client->dev, "%s chip ID %04x\n", devname, chipid);
-
-done:
-       mt9t112_s_power(&priv->subdev, 0);
-       return ret;
-}
-
-static int mt9t112_probe(struct i2c_client *client,
-                        const struct i2c_device_id *did)
-{
-       struct mt9t112_priv *priv;
-       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
-       struct v4l2_rect rect = {
-               .width = VGA_WIDTH,
-               .height = VGA_HEIGHT,
-               .left = (MAX_WIDTH - VGA_WIDTH) / 2,
-               .top = (MAX_HEIGHT - VGA_HEIGHT) / 2,
-       };
-       int ret;
-
-       if (!ssdd || !ssdd->drv_priv) {
-               dev_err(&client->dev, "mt9t112: missing platform data!\n");
-               return -EINVAL;
-       }
-
-       priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-
-       priv->info = ssdd->drv_priv;
-
-       v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops);
-
-       priv->clk = v4l2_clk_get(&client->dev, "mclk");
-       if (IS_ERR(priv->clk))
-               return PTR_ERR(priv->clk);
-
-       ret = mt9t112_camera_probe(client);
-
-       /* Cannot fail: using the default supported pixel code */
-       if (!ret)
-               mt9t112_set_params(priv, &rect, MEDIA_BUS_FMT_UYVY8_2X8);
-       else
-               v4l2_clk_put(priv->clk);
-
-       return ret;
-}
-
-static int mt9t112_remove(struct i2c_client *client)
-{
-       struct mt9t112_priv *priv = to_mt9t112(client);
-
-       v4l2_clk_put(priv->clk);
-       return 0;
-}
-
-static const struct i2c_device_id mt9t112_id[] = {
-       { "mt9t112", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, mt9t112_id);
-
-static struct i2c_driver mt9t112_i2c_driver = {
-       .driver = {
-               .name = "mt9t112",
-       },
-       .probe    = mt9t112_probe,
-       .remove   = mt9t112_remove,
-       .id_table = mt9t112_id,
-};
-
-module_i2c_driver(mt9t112_i2c_driver);
-
-MODULE_DESCRIPTION("SoC Camera driver for mt9t112");
-MODULE_AUTHOR("Kuninori Morimoto");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/soc_camera/mt9v022.c b/drivers/media/i2c/soc_camera/mt9v022.c
deleted file mode 100644 (file)
index 6d922b1..0000000
+++ /dev/null
@@ -1,1012 +0,0 @@
-/*
- * Driver for MT9V022 CMOS Image Sensor from Micron
- *
- * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
- *
- * 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.
- */
-
-#include <linux/videodev2.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/delay.h>
-#include <linux/log2.h>
-#include <linux/module.h>
-
-#include <media/i2c/mt9v022.h>
-#include <media/soc_camera.h>
-#include <media/drv-intf/soc_mediabus.h>
-#include <media/v4l2-subdev.h>
-#include <media/v4l2-clk.h>
-#include <media/v4l2-ctrls.h>
-
-/*
- * mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c
- * The platform has to define struct i2c_board_info objects and link to them
- * from struct soc_camera_host_desc
- */
-
-static char *sensor_type;
-module_param(sensor_type, charp, S_IRUGO);
-MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\"");
-
-/* mt9v022 selected register addresses */
-#define MT9V022_CHIP_VERSION           0x00
-#define MT9V022_COLUMN_START           0x01
-#define MT9V022_ROW_START              0x02
-#define MT9V022_WINDOW_HEIGHT          0x03
-#define MT9V022_WINDOW_WIDTH           0x04
-#define MT9V022_HORIZONTAL_BLANKING    0x05
-#define MT9V022_VERTICAL_BLANKING      0x06
-#define MT9V022_CHIP_CONTROL           0x07
-#define MT9V022_SHUTTER_WIDTH1         0x08
-#define MT9V022_SHUTTER_WIDTH2         0x09
-#define MT9V022_SHUTTER_WIDTH_CTRL     0x0a
-#define MT9V022_TOTAL_SHUTTER_WIDTH    0x0b
-#define MT9V022_RESET                  0x0c
-#define MT9V022_READ_MODE              0x0d
-#define MT9V022_MONITOR_MODE           0x0e
-#define MT9V022_PIXEL_OPERATION_MODE   0x0f
-#define MT9V022_LED_OUT_CONTROL                0x1b
-#define MT9V022_ADC_MODE_CONTROL       0x1c
-#define MT9V022_REG32                  0x20
-#define MT9V022_ANALOG_GAIN            0x35
-#define MT9V022_BLACK_LEVEL_CALIB_CTRL 0x47
-#define MT9V022_PIXCLK_FV_LV           0x74
-#define MT9V022_DIGITAL_TEST_PATTERN   0x7f
-#define MT9V022_AEC_AGC_ENABLE         0xAF
-#define MT9V022_MAX_TOTAL_SHUTTER_WIDTH        0xBD
-
-/* mt9v024 partial list register addresses changes with respect to mt9v022 */
-#define MT9V024_PIXCLK_FV_LV           0x72
-#define MT9V024_MAX_TOTAL_SHUTTER_WIDTH        0xAD
-
-/* Progressive scan, master, defaults */
-#define MT9V022_CHIP_CONTROL_DEFAULT   0x188
-
-#define MT9V022_MAX_WIDTH              752
-#define MT9V022_MAX_HEIGHT             480
-#define MT9V022_MIN_WIDTH              48
-#define MT9V022_MIN_HEIGHT             32
-#define MT9V022_COLUMN_SKIP            1
-#define MT9V022_ROW_SKIP               4
-
-#define MT9V022_HORIZONTAL_BLANKING_MIN        43
-#define MT9V022_HORIZONTAL_BLANKING_MAX        1023
-#define MT9V022_HORIZONTAL_BLANKING_DEF        94
-#define MT9V022_VERTICAL_BLANKING_MIN  2
-#define MT9V022_VERTICAL_BLANKING_MAX  3000
-#define MT9V022_VERTICAL_BLANKING_DEF  45
-
-#define is_mt9v022_rev3(id)    (id == 0x1313)
-#define is_mt9v024(id)         (id == 0x1324)
-
-/* MT9V022 has only one fixed colorspace per pixelcode */
-struct mt9v022_datafmt {
-       u32     code;
-       enum v4l2_colorspace            colorspace;
-};
-
-/* Find a data format by a pixel code in an array */
-static const struct mt9v022_datafmt *mt9v022_find_datafmt(
-       u32 code, const struct mt9v022_datafmt *fmt,
-       int n)
-{
-       int i;
-       for (i = 0; i < n; i++)
-               if (fmt[i].code == code)
-                       return fmt + i;
-
-       return NULL;
-}
-
-static const struct mt9v022_datafmt mt9v022_colour_fmts[] = {
-       /*
-        * Order important: first natively supported,
-        * second supported with a GPIO extender
-        */
-       {MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB},
-       {MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
-};
-
-static const struct mt9v022_datafmt mt9v022_monochrome_fmts[] = {
-       /* Order important - see above */
-       {MEDIA_BUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG},
-       {MEDIA_BUS_FMT_Y8_1X8, V4L2_COLORSPACE_JPEG},
-};
-
-/* only registers with different addresses on different mt9v02x sensors */
-struct mt9v02x_register {
-       u8      max_total_shutter_width;
-       u8      pixclk_fv_lv;
-};
-
-static const struct mt9v02x_register mt9v022_register = {
-       .max_total_shutter_width        = MT9V022_MAX_TOTAL_SHUTTER_WIDTH,
-       .pixclk_fv_lv                   = MT9V022_PIXCLK_FV_LV,
-};
-
-static const struct mt9v02x_register mt9v024_register = {
-       .max_total_shutter_width        = MT9V024_MAX_TOTAL_SHUTTER_WIDTH,
-       .pixclk_fv_lv                   = MT9V024_PIXCLK_FV_LV,
-};
-
-enum mt9v022_model {
-       MT9V022IX7ATM,
-       MT9V022IX7ATC,
-};
-
-struct mt9v022 {
-       struct v4l2_subdev subdev;
-       struct v4l2_ctrl_handler hdl;
-       struct {
-               /* exposure/auto-exposure cluster */
-               struct v4l2_ctrl *autoexposure;
-               struct v4l2_ctrl *exposure;
-       };
-       struct {
-               /* gain/auto-gain cluster */
-               struct v4l2_ctrl *autogain;
-               struct v4l2_ctrl *gain;
-       };
-       struct v4l2_ctrl *hblank;
-       struct v4l2_ctrl *vblank;
-       struct v4l2_rect rect;  /* Sensor window */
-       struct v4l2_clk *clk;
-       const struct mt9v022_datafmt *fmt;
-       const struct mt9v022_datafmt *fmts;
-       const struct mt9v02x_register *reg;
-       int num_fmts;
-       enum mt9v022_model model;
-       u16 chip_control;
-       u16 chip_version;
-       unsigned short y_skip_top;      /* Lines to skip at the top */
-};
-
-static struct mt9v022 *to_mt9v022(const struct i2c_client *client)
-{
-       return container_of(i2c_get_clientdata(client), struct mt9v022, subdev);
-}
-
-static int reg_read(struct i2c_client *client, const u8 reg)
-{
-       return i2c_smbus_read_word_swapped(client, reg);
-}
-
-static int reg_write(struct i2c_client *client, const u8 reg,
-                    const u16 data)
-{
-       return i2c_smbus_write_word_swapped(client, reg, data);
-}
-
-static int reg_set(struct i2c_client *client, const u8 reg,
-                  const u16 data)
-{
-       int ret;
-
-       ret = reg_read(client, reg);
-       if (ret < 0)
-               return ret;
-       return reg_write(client, reg, ret | data);
-}
-
-static int reg_clear(struct i2c_client *client, const u8 reg,
-                    const u16 data)
-{
-       int ret;
-
-       ret = reg_read(client, reg);
-       if (ret < 0)
-               return ret;
-       return reg_write(client, reg, ret & ~data);
-}
-
-static int mt9v022_init(struct i2c_client *client)
-{
-       struct mt9v022 *mt9v022 = to_mt9v022(client);
-       int ret;
-
-       /*
-        * Almost the default mode: master, parallel, simultaneous, and an
-        * undocumented bit 0x200, which is present in table 7, but not in 8,
-        * plus snapshot mode to disable scan for now
-        */
-       mt9v022->chip_control |= 0x10;
-       ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
-       if (!ret)
-               ret = reg_write(client, MT9V022_READ_MODE, 0x300);
-
-       /* All defaults */
-       if (!ret)
-               /* AEC, AGC on */
-               ret = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x3);
-       if (!ret)
-               ret = reg_write(client, MT9V022_ANALOG_GAIN, 16);
-       if (!ret)
-               ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, 480);
-       if (!ret)
-               ret = reg_write(client, mt9v022->reg->max_total_shutter_width, 480);
-       if (!ret)
-               /* default - auto */
-               ret = reg_clear(client, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1);
-       if (!ret)
-               ret = reg_write(client, MT9V022_DIGITAL_TEST_PATTERN, 0);
-       if (!ret)
-               return v4l2_ctrl_handler_setup(&mt9v022->hdl);
-
-       return ret;
-}
-
-static int mt9v022_s_stream(struct v4l2_subdev *sd, int enable)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9v022 *mt9v022 = to_mt9v022(client);
-
-       if (enable) {
-               /* Switch to master "normal" mode */
-               mt9v022->chip_control &= ~0x10;
-               if (is_mt9v022_rev3(mt9v022->chip_version) ||
-                   is_mt9v024(mt9v022->chip_version)) {
-                       /*
-                        * Unset snapshot mode specific settings: clear bit 9
-                        * and bit 2 in reg. 0x20 when in normal mode.
-                        */
-                       if (reg_clear(client, MT9V022_REG32, 0x204))
-                               return -EIO;
-               }
-       } else {
-               /* Switch to snapshot mode */
-               mt9v022->chip_control |= 0x10;
-               if (is_mt9v022_rev3(mt9v022->chip_version) ||
-                   is_mt9v024(mt9v022->chip_version)) {
-                       /*
-                        * Required settings for snapshot mode: set bit 9
-                        * (RST enable) and bit 2 (CR enable) in reg. 0x20
-                        * See TechNote TN0960 or TN-09-225.
-                        */
-                       if (reg_set(client, MT9V022_REG32, 0x204))
-                               return -EIO;
-               }
-       }
-
-       if (reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control) < 0)
-               return -EIO;
-       return 0;
-}
-
-static int mt9v022_set_selection(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_selection *sel)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9v022 *mt9v022 = to_mt9v022(client);
-       struct v4l2_rect rect = sel->r;
-       int min_row, min_blank;
-       int ret;
-
-       if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
-           sel->target != V4L2_SEL_TGT_CROP)
-               return -EINVAL;
-
-       /* Bayer format - even size lengths */
-       if (mt9v022->fmts == mt9v022_colour_fmts) {
-               rect.width      = ALIGN(rect.width, 2);
-               rect.height     = ALIGN(rect.height, 2);
-               /* Let the user play with the starting pixel */
-       }
-
-       soc_camera_limit_side(&rect.left, &rect.width,
-                    MT9V022_COLUMN_SKIP, MT9V022_MIN_WIDTH, MT9V022_MAX_WIDTH);
-
-       soc_camera_limit_side(&rect.top, &rect.height,
-                    MT9V022_ROW_SKIP, MT9V022_MIN_HEIGHT, MT9V022_MAX_HEIGHT);
-
-       /* Like in example app. Contradicts the datasheet though */
-       ret = reg_read(client, MT9V022_AEC_AGC_ENABLE);
-       if (ret >= 0) {
-               if (ret & 1) /* Autoexposure */
-                       ret = reg_write(client, mt9v022->reg->max_total_shutter_width,
-                                       rect.height + mt9v022->y_skip_top + 43);
-               /*
-                * If autoexposure is off, there is no need to set
-                * MT9V022_TOTAL_SHUTTER_WIDTH here. Autoexposure can be off
-                * only if the user has set exposure manually, using the
-                * V4L2_CID_EXPOSURE_AUTO with the value V4L2_EXPOSURE_MANUAL.
-                * In this case the register MT9V022_TOTAL_SHUTTER_WIDTH
-                * already contains the correct value.
-                */
-       }
-       /* Setup frame format: defaults apart from width and height */
-       if (!ret)
-               ret = reg_write(client, MT9V022_COLUMN_START, rect.left);
-       if (!ret)
-               ret = reg_write(client, MT9V022_ROW_START, rect.top);
-       /*
-        * mt9v022: min total row time is 660 columns, min blanking is 43
-        * mt9v024: min total row time is 690 columns, min blanking is 61
-        */
-       if (is_mt9v024(mt9v022->chip_version)) {
-               min_row = 690;
-               min_blank = 61;
-       } else {
-               min_row = 660;
-               min_blank = 43;
-       }
-       if (!ret)
-               ret = v4l2_ctrl_s_ctrl(mt9v022->hblank,
-                               rect.width > min_row - min_blank ?
-                               min_blank : min_row - rect.width);
-       if (!ret)
-               ret = v4l2_ctrl_s_ctrl(mt9v022->vblank, 45);
-       if (!ret)
-               ret = reg_write(client, MT9V022_WINDOW_WIDTH, rect.width);
-       if (!ret)
-               ret = reg_write(client, MT9V022_WINDOW_HEIGHT,
-                               rect.height + mt9v022->y_skip_top);
-
-       if (ret < 0)
-               return ret;
-
-       dev_dbg(&client->dev, "Frame %dx%d pixel\n", rect.width, rect.height);
-
-       mt9v022->rect = rect;
-
-       return 0;
-}
-
-static int mt9v022_get_selection(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_selection *sel)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9v022 *mt9v022 = to_mt9v022(client);
-
-       if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
-               return -EINVAL;
-
-       switch (sel->target) {
-       case V4L2_SEL_TGT_CROP_BOUNDS:
-               sel->r.left = MT9V022_COLUMN_SKIP;
-               sel->r.top = MT9V022_ROW_SKIP;
-               sel->r.width = MT9V022_MAX_WIDTH;
-               sel->r.height = MT9V022_MAX_HEIGHT;
-               return 0;
-       case V4L2_SEL_TGT_CROP:
-               sel->r = mt9v022->rect;
-               return 0;
-       default:
-               return -EINVAL;
-       }
-}
-
-static int mt9v022_get_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_format *format)
-{
-       struct v4l2_mbus_framefmt *mf = &format->format;
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9v022 *mt9v022 = to_mt9v022(client);
-
-       if (format->pad)
-               return -EINVAL;
-
-       mf->width       = mt9v022->rect.width;
-       mf->height      = mt9v022->rect.height;
-       mf->code        = mt9v022->fmt->code;
-       mf->colorspace  = mt9v022->fmt->colorspace;
-       mf->field       = V4L2_FIELD_NONE;
-
-       return 0;
-}
-
-static int mt9v022_s_fmt(struct v4l2_subdev *sd,
-                        const struct mt9v022_datafmt *fmt,
-                        struct v4l2_mbus_framefmt *mf)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9v022 *mt9v022 = to_mt9v022(client);
-       struct v4l2_subdev_selection sel = {
-               .which = V4L2_SUBDEV_FORMAT_ACTIVE,
-               .target = V4L2_SEL_TGT_CROP,
-               .r.left = mt9v022->rect.left,
-               .r.top = mt9v022->rect.top,
-               .r.width = mf->width,
-               .r.height = mf->height,
-       };
-       int ret;
-
-       /*
-        * The caller provides a supported format, as verified per call to
-        * .set_fmt(FORMAT_TRY), datawidth is from our supported format list
-        */
-       switch (mf->code) {
-       case MEDIA_BUS_FMT_Y8_1X8:
-       case MEDIA_BUS_FMT_Y10_1X10:
-               if (mt9v022->model != MT9V022IX7ATM)
-                       return -EINVAL;
-               break;
-       case MEDIA_BUS_FMT_SBGGR8_1X8:
-       case MEDIA_BUS_FMT_SBGGR10_1X10:
-               if (mt9v022->model != MT9V022IX7ATC)
-                       return -EINVAL;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       /* No support for scaling on this camera, just crop. */
-       ret = mt9v022_set_selection(sd, NULL, &sel);
-       if (!ret) {
-               mf->width       = mt9v022->rect.width;
-               mf->height      = mt9v022->rect.height;
-               mt9v022->fmt    = fmt;
-               mf->colorspace  = fmt->colorspace;
-       }
-
-       return ret;
-}
-
-static int mt9v022_set_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_format *format)
-{
-       struct v4l2_mbus_framefmt *mf = &format->format;
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9v022 *mt9v022 = to_mt9v022(client);
-       const struct mt9v022_datafmt *fmt;
-       int align = mf->code == MEDIA_BUS_FMT_SBGGR8_1X8 ||
-               mf->code == MEDIA_BUS_FMT_SBGGR10_1X10;
-
-       if (format->pad)
-               return -EINVAL;
-
-       v4l_bound_align_image(&mf->width, MT9V022_MIN_WIDTH,
-               MT9V022_MAX_WIDTH, align,
-               &mf->height, MT9V022_MIN_HEIGHT + mt9v022->y_skip_top,
-               MT9V022_MAX_HEIGHT + mt9v022->y_skip_top, align, 0);
-
-       fmt = mt9v022_find_datafmt(mf->code, mt9v022->fmts,
-                                  mt9v022->num_fmts);
-       if (!fmt) {
-               fmt = mt9v022->fmt;
-               mf->code = fmt->code;
-       }
-
-       mf->colorspace  = fmt->colorspace;
-
-       if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
-               return mt9v022_s_fmt(sd, fmt, mf);
-       cfg->try_fmt = *mf;
-       return 0;
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int mt9v022_g_register(struct v4l2_subdev *sd,
-                             struct v4l2_dbg_register *reg)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (reg->reg > 0xff)
-               return -EINVAL;
-
-       reg->size = 2;
-       reg->val = reg_read(client, reg->reg);
-
-       if (reg->val > 0xffff)
-               return -EIO;
-
-       return 0;
-}
-
-static int mt9v022_s_register(struct v4l2_subdev *sd,
-                             const struct v4l2_dbg_register *reg)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (reg->reg > 0xff)
-               return -EINVAL;
-
-       if (reg_write(client, reg->reg, reg->val) < 0)
-               return -EIO;
-
-       return 0;
-}
-#endif
-
-static int mt9v022_s_power(struct v4l2_subdev *sd, int on)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
-       struct mt9v022 *mt9v022 = to_mt9v022(client);
-
-       return soc_camera_set_power(&client->dev, ssdd, mt9v022->clk, on);
-}
-
-static int mt9v022_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
-{
-       struct mt9v022 *mt9v022 = container_of(ctrl->handler,
-                                              struct mt9v022, hdl);
-       struct v4l2_subdev *sd = &mt9v022->subdev;
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct v4l2_ctrl *gain = mt9v022->gain;
-       struct v4l2_ctrl *exp = mt9v022->exposure;
-       unsigned long range;
-       int data;
-
-       switch (ctrl->id) {
-       case V4L2_CID_AUTOGAIN:
-               data = reg_read(client, MT9V022_ANALOG_GAIN);
-               if (data < 0)
-                       return -EIO;
-
-               range = gain->maximum - gain->minimum;
-               gain->val = ((data - 16) * range + 24) / 48 + gain->minimum;
-               return 0;
-       case V4L2_CID_EXPOSURE_AUTO:
-               data = reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH);
-               if (data < 0)
-                       return -EIO;
-
-               range = exp->maximum - exp->minimum;
-               exp->val = ((data - 1) * range + 239) / 479 + exp->minimum;
-               return 0;
-       case V4L2_CID_HBLANK:
-               data = reg_read(client, MT9V022_HORIZONTAL_BLANKING);
-               if (data < 0)
-                       return -EIO;
-               ctrl->val = data;
-               return 0;
-       case V4L2_CID_VBLANK:
-               data = reg_read(client, MT9V022_VERTICAL_BLANKING);
-               if (data < 0)
-                       return -EIO;
-               ctrl->val = data;
-               return 0;
-       }
-       return -EINVAL;
-}
-
-static int mt9v022_s_ctrl(struct v4l2_ctrl *ctrl)
-{
-       struct mt9v022 *mt9v022 = container_of(ctrl->handler,
-                                              struct mt9v022, hdl);
-       struct v4l2_subdev *sd = &mt9v022->subdev;
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int data;
-
-       switch (ctrl->id) {
-       case V4L2_CID_VFLIP:
-               if (ctrl->val)
-                       data = reg_set(client, MT9V022_READ_MODE, 0x10);
-               else
-                       data = reg_clear(client, MT9V022_READ_MODE, 0x10);
-               if (data < 0)
-                       return -EIO;
-               return 0;
-       case V4L2_CID_HFLIP:
-               if (ctrl->val)
-                       data = reg_set(client, MT9V022_READ_MODE, 0x20);
-               else
-                       data = reg_clear(client, MT9V022_READ_MODE, 0x20);
-               if (data < 0)
-                       return -EIO;
-               return 0;
-       case V4L2_CID_AUTOGAIN:
-               if (ctrl->val) {
-                       if (reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0)
-                               return -EIO;
-               } else {
-                       struct v4l2_ctrl *gain = mt9v022->gain;
-                       /* mt9v022 has minimum == default */
-                       unsigned long range = gain->maximum - gain->minimum;
-                       /* Valid values 16 to 64, 32 to 64 must be even. */
-                       unsigned long gain_val = ((gain->val - (s32)gain->minimum) *
-                                             48 + range / 2) / range + 16;
-
-                       if (gain_val >= 32)
-                               gain_val &= ~1;
-
-                       /*
-                        * The user wants to set gain manually, hope, she
-                        * knows, what she's doing... Switch AGC off.
-                        */
-                       if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0)
-                               return -EIO;
-
-                       dev_dbg(&client->dev, "Setting gain from %d to %lu\n",
-                               reg_read(client, MT9V022_ANALOG_GAIN), gain_val);
-                       if (reg_write(client, MT9V022_ANALOG_GAIN, gain_val) < 0)
-                               return -EIO;
-               }
-               return 0;
-       case V4L2_CID_EXPOSURE_AUTO:
-               if (ctrl->val == V4L2_EXPOSURE_AUTO) {
-                       data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x1);
-               } else {
-                       struct v4l2_ctrl *exp = mt9v022->exposure;
-                       unsigned long range = exp->maximum - exp->minimum;
-                       unsigned long shutter = ((exp->val - (s32)exp->minimum) *
-                                       479 + range / 2) / range + 1;
-
-                       /*
-                        * The user wants to set shutter width manually, hope,
-                        * she knows, what she's doing... Switch AEC off.
-                        */
-                       data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1);
-                       if (data < 0)
-                               return -EIO;
-                       dev_dbg(&client->dev, "Shutter width from %d to %lu\n",
-                                       reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH),
-                                       shutter);
-                       if (reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH,
-                                               shutter) < 0)
-                               return -EIO;
-               }
-               return 0;
-       case V4L2_CID_HBLANK:
-               if (reg_write(client, MT9V022_HORIZONTAL_BLANKING,
-                               ctrl->val) < 0)
-                       return -EIO;
-               return 0;
-       case V4L2_CID_VBLANK:
-               if (reg_write(client, MT9V022_VERTICAL_BLANKING,
-                               ctrl->val) < 0)
-                       return -EIO;
-               return 0;
-       }
-       return -EINVAL;
-}
-
-/*
- * Interface active, can use i2c. If it fails, it can indeed mean, that
- * this wasn't our capture interface, so, we wait for the right one
- */
-static int mt9v022_video_probe(struct i2c_client *client)
-{
-       struct mt9v022 *mt9v022 = to_mt9v022(client);
-       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
-       s32 data;
-       int ret;
-       unsigned long flags;
-
-       ret = mt9v022_s_power(&mt9v022->subdev, 1);
-       if (ret < 0)
-               return ret;
-
-       /* Read out the chip version register */
-       data = reg_read(client, MT9V022_CHIP_VERSION);
-
-       /* must be 0x1311, 0x1313 or 0x1324 */
-       if (data != 0x1311 && data != 0x1313 && data != 0x1324) {
-               ret = -ENODEV;
-               dev_info(&client->dev, "No MT9V022 found, ID register 0x%x\n",
-                        data);
-               goto ei2c;
-       }
-
-       mt9v022->chip_version = data;
-
-       mt9v022->reg = is_mt9v024(data) ? &mt9v024_register :
-                       &mt9v022_register;
-
-       /* Soft reset */
-       ret = reg_write(client, MT9V022_RESET, 1);
-       if (ret < 0)
-               goto ei2c;
-       /* 15 clock cycles */
-       udelay(200);
-       if (reg_read(client, MT9V022_RESET)) {
-               dev_err(&client->dev, "Resetting MT9V022 failed!\n");
-               if (ret > 0)
-                       ret = -EIO;
-               goto ei2c;
-       }
-
-       /* Set monochrome or colour sensor type */
-       if (sensor_type && (!strcmp("colour", sensor_type) ||
-                           !strcmp("color", sensor_type))) {
-               ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 4 | 0x11);
-               mt9v022->model = MT9V022IX7ATC;
-               mt9v022->fmts = mt9v022_colour_fmts;
-       } else {
-               ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 0x11);
-               mt9v022->model = MT9V022IX7ATM;
-               mt9v022->fmts = mt9v022_monochrome_fmts;
-       }
-
-       if (ret < 0)
-               goto ei2c;
-
-       mt9v022->num_fmts = 0;
-
-       /*
-        * This is a 10bit sensor, so by default we only allow 10bit.
-        * The platform may support different bus widths due to
-        * different routing of the data lines.
-        */
-       if (ssdd->query_bus_param)
-               flags = ssdd->query_bus_param(ssdd);
-       else
-               flags = SOCAM_DATAWIDTH_10;
-
-       if (flags & SOCAM_DATAWIDTH_10)
-               mt9v022->num_fmts++;
-       else
-               mt9v022->fmts++;
-
-       if (flags & SOCAM_DATAWIDTH_8)
-               mt9v022->num_fmts++;
-
-       mt9v022->fmt = &mt9v022->fmts[0];
-
-       dev_info(&client->dev, "Detected a MT9V022 chip ID %x, %s sensor\n",
-                data, mt9v022->model == MT9V022IX7ATM ?
-                "monochrome" : "colour");
-
-       ret = mt9v022_init(client);
-       if (ret < 0)
-               dev_err(&client->dev, "Failed to initialise the camera\n");
-
-ei2c:
-       mt9v022_s_power(&mt9v022->subdev, 0);
-       return ret;
-}
-
-static int mt9v022_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9v022 *mt9v022 = to_mt9v022(client);
-
-       *lines = mt9v022->y_skip_top;
-
-       return 0;
-}
-
-static const struct v4l2_ctrl_ops mt9v022_ctrl_ops = {
-       .g_volatile_ctrl = mt9v022_g_volatile_ctrl,
-       .s_ctrl = mt9v022_s_ctrl,
-};
-
-static const struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = {
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       .g_register     = mt9v022_g_register,
-       .s_register     = mt9v022_s_register,
-#endif
-       .s_power        = mt9v022_s_power,
-};
-
-static int mt9v022_enum_mbus_code(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_mbus_code_enum *code)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9v022 *mt9v022 = to_mt9v022(client);
-
-       if (code->pad || code->index >= mt9v022->num_fmts)
-               return -EINVAL;
-
-       code->code = mt9v022->fmts[code->index].code;
-       return 0;
-}
-
-static int mt9v022_g_mbus_config(struct v4l2_subdev *sd,
-                               struct v4l2_mbus_config *cfg)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
-
-       cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE |
-               V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING |
-               V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW |
-               V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW |
-               V4L2_MBUS_DATA_ACTIVE_HIGH;
-       cfg->type = V4L2_MBUS_PARALLEL;
-       cfg->flags = soc_camera_apply_board_flags(ssdd, cfg);
-
-       return 0;
-}
-
-static int mt9v022_s_mbus_config(struct v4l2_subdev *sd,
-                                const struct v4l2_mbus_config *cfg)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
-       struct mt9v022 *mt9v022 = to_mt9v022(client);
-       unsigned long flags = soc_camera_apply_board_flags(ssdd, cfg);
-       unsigned int bps = soc_mbus_get_fmtdesc(mt9v022->fmt->code)->bits_per_sample;
-       int ret;
-       u16 pixclk = 0;
-
-       if (ssdd->set_bus_param) {
-               ret = ssdd->set_bus_param(ssdd, 1 << (bps - 1));
-               if (ret)
-                       return ret;
-       } else if (bps != 10) {
-               /*
-                * Without board specific bus width settings we only support the
-                * sensors native bus width
-                */
-               return -EINVAL;
-       }
-
-       if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
-               pixclk |= 0x10;
-
-       if (!(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH))
-               pixclk |= 0x1;
-
-       if (!(flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH))
-               pixclk |= 0x2;
-
-       ret = reg_write(client, mt9v022->reg->pixclk_fv_lv, pixclk);
-       if (ret < 0)
-               return ret;
-
-       if (!(flags & V4L2_MBUS_MASTER))
-               mt9v022->chip_control &= ~0x8;
-
-       ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
-       if (ret < 0)
-               return ret;
-
-       dev_dbg(&client->dev, "Calculated pixclk 0x%x, chip control 0x%x\n",
-               pixclk, mt9v022->chip_control);
-
-       return 0;
-}
-
-static const struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = {
-       .s_stream       = mt9v022_s_stream,
-       .g_mbus_config  = mt9v022_g_mbus_config,
-       .s_mbus_config  = mt9v022_s_mbus_config,
-};
-
-static const struct v4l2_subdev_sensor_ops mt9v022_subdev_sensor_ops = {
-       .g_skip_top_lines       = mt9v022_g_skip_top_lines,
-};
-
-static const struct v4l2_subdev_pad_ops mt9v022_subdev_pad_ops = {
-       .enum_mbus_code = mt9v022_enum_mbus_code,
-       .get_selection  = mt9v022_get_selection,
-       .set_selection  = mt9v022_set_selection,
-       .get_fmt        = mt9v022_get_fmt,
-       .set_fmt        = mt9v022_set_fmt,
-};
-
-static const struct v4l2_subdev_ops mt9v022_subdev_ops = {
-       .core   = &mt9v022_subdev_core_ops,
-       .video  = &mt9v022_subdev_video_ops,
-       .sensor = &mt9v022_subdev_sensor_ops,
-       .pad    = &mt9v022_subdev_pad_ops,
-};
-
-static int mt9v022_probe(struct i2c_client *client,
-                        const struct i2c_device_id *did)
-{
-       struct mt9v022 *mt9v022;
-       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
-       struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
-       struct mt9v022_platform_data *pdata;
-       int ret;
-
-       if (!ssdd) {
-               dev_err(&client->dev, "MT9V022 driver needs platform data\n");
-               return -EINVAL;
-       }
-
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
-               dev_warn(&adapter->dev,
-                        "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
-               return -EIO;
-       }
-
-       mt9v022 = devm_kzalloc(&client->dev, sizeof(struct mt9v022), GFP_KERNEL);
-       if (!mt9v022)
-               return -ENOMEM;
-
-       pdata = ssdd->drv_priv;
-       v4l2_i2c_subdev_init(&mt9v022->subdev, client, &mt9v022_subdev_ops);
-       v4l2_ctrl_handler_init(&mt9v022->hdl, 6);
-       v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
-                       V4L2_CID_VFLIP, 0, 1, 1, 0);
-       v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
-                       V4L2_CID_HFLIP, 0, 1, 1, 0);
-       mt9v022->autogain = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
-                       V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
-       mt9v022->gain = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
-                       V4L2_CID_GAIN, 0, 127, 1, 64);
-
-       /*
-        * Simulated autoexposure. If enabled, we calculate shutter width
-        * ourselves in the driver based on vertical blanking and frame width
-        */
-       mt9v022->autoexposure = v4l2_ctrl_new_std_menu(&mt9v022->hdl,
-                       &mt9v022_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0,
-                       V4L2_EXPOSURE_AUTO);
-       mt9v022->exposure = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
-                       V4L2_CID_EXPOSURE, 1, 255, 1, 255);
-
-       mt9v022->hblank = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
-                       V4L2_CID_HBLANK, MT9V022_HORIZONTAL_BLANKING_MIN,
-                       MT9V022_HORIZONTAL_BLANKING_MAX, 1,
-                       MT9V022_HORIZONTAL_BLANKING_DEF);
-
-       mt9v022->vblank = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
-                       V4L2_CID_VBLANK, MT9V022_VERTICAL_BLANKING_MIN,
-                       MT9V022_VERTICAL_BLANKING_MAX, 1,
-                       MT9V022_VERTICAL_BLANKING_DEF);
-
-       mt9v022->subdev.ctrl_handler = &mt9v022->hdl;
-       if (mt9v022->hdl.error) {
-               int err = mt9v022->hdl.error;
-
-               dev_err(&client->dev, "control initialisation err %d\n", err);
-               return err;
-       }
-       v4l2_ctrl_auto_cluster(2, &mt9v022->autoexposure,
-                               V4L2_EXPOSURE_MANUAL, true);
-       v4l2_ctrl_auto_cluster(2, &mt9v022->autogain, 0, true);
-
-       mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT;
-
-       /*
-        * On some platforms the first read out line is corrupted.
-        * Workaround it by skipping if indicated by platform data.
-        */
-       mt9v022->y_skip_top     = pdata ? pdata->y_skip_top : 0;
-       mt9v022->rect.left      = MT9V022_COLUMN_SKIP;
-       mt9v022->rect.top       = MT9V022_ROW_SKIP;
-       mt9v022->rect.width     = MT9V022_MAX_WIDTH;
-       mt9v022->rect.height    = MT9V022_MAX_HEIGHT;
-
-       mt9v022->clk = v4l2_clk_get(&client->dev, "mclk");
-       if (IS_ERR(mt9v022->clk)) {
-               ret = PTR_ERR(mt9v022->clk);
-               goto eclkget;
-       }
-
-       ret = mt9v022_video_probe(client);
-       if (ret) {
-               v4l2_clk_put(mt9v022->clk);
-eclkget:
-               v4l2_ctrl_handler_free(&mt9v022->hdl);
-       }
-
-       return ret;
-}
-
-static int mt9v022_remove(struct i2c_client *client)
-{
-       struct mt9v022 *mt9v022 = to_mt9v022(client);
-       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
-
-       v4l2_clk_put(mt9v022->clk);
-       v4l2_device_unregister_subdev(&mt9v022->subdev);
-       if (ssdd->free_bus)
-               ssdd->free_bus(ssdd);
-       v4l2_ctrl_handler_free(&mt9v022->hdl);
-
-       return 0;
-}
-static const struct i2c_device_id mt9v022_id[] = {
-       { "mt9v022", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, mt9v022_id);
-
-static struct i2c_driver mt9v022_i2c_driver = {
-       .driver = {
-               .name = "mt9v022",
-       },
-       .probe          = mt9v022_probe,
-       .remove         = mt9v022_remove,
-       .id_table       = mt9v022_id,
-};
-
-module_i2c_driver(mt9v022_i2c_driver);
-
-MODULE_DESCRIPTION("Micron MT9V022 Camera driver");
-MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/soc_camera/ov5642.c b/drivers/media/i2c/soc_camera/ov5642.c
deleted file mode 100644 (file)
index 0931898..0000000
+++ /dev/null
@@ -1,1087 +0,0 @@
-/*
- * Driver for OV5642 CMOS Image Sensor from Omnivision
- *
- * Copyright (C) 2011, Bastian Hecht <hechtb@gmail.com>
- *
- * Based on Sony IMX074 Camera Driver
- * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- *
- * Based on Omnivision OV7670 Camera Driver
- * Copyright (C) 2006-7 Jonathan Corbet <corbet@lwn.net>
- *
- * 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.
- */
-
-#include <linux/bitops.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/videodev2.h>
-#include <linux/module.h>
-#include <linux/v4l2-mediabus.h>
-
-#include <media/soc_camera.h>
-#include <media/v4l2-clk.h>
-#include <media/v4l2-subdev.h>
-
-/* OV5642 registers */
-#define REG_CHIP_ID_HIGH               0x300a
-#define REG_CHIP_ID_LOW                        0x300b
-
-#define REG_WINDOW_START_X_HIGH                0x3800
-#define REG_WINDOW_START_X_LOW         0x3801
-#define REG_WINDOW_START_Y_HIGH                0x3802
-#define REG_WINDOW_START_Y_LOW         0x3803
-#define REG_WINDOW_WIDTH_HIGH          0x3804
-#define REG_WINDOW_WIDTH_LOW           0x3805
-#define REG_WINDOW_HEIGHT_HIGH         0x3806
-#define REG_WINDOW_HEIGHT_LOW          0x3807
-#define REG_OUT_WIDTH_HIGH             0x3808
-#define REG_OUT_WIDTH_LOW              0x3809
-#define REG_OUT_HEIGHT_HIGH            0x380a
-#define REG_OUT_HEIGHT_LOW             0x380b
-#define REG_OUT_TOTAL_WIDTH_HIGH       0x380c
-#define REG_OUT_TOTAL_WIDTH_LOW                0x380d
-#define REG_OUT_TOTAL_HEIGHT_HIGH      0x380e
-#define REG_OUT_TOTAL_HEIGHT_LOW       0x380f
-#define REG_OUTPUT_FORMAT              0x4300
-#define REG_ISP_CTRL_01                        0x5001
-#define REG_AVG_WINDOW_END_X_HIGH      0x5682
-#define REG_AVG_WINDOW_END_X_LOW       0x5683
-#define REG_AVG_WINDOW_END_Y_HIGH      0x5686
-#define REG_AVG_WINDOW_END_Y_LOW       0x5687
-
-/* active pixel array size */
-#define OV5642_SENSOR_SIZE_X   2592
-#define OV5642_SENSOR_SIZE_Y   1944
-
-/*
- * About OV5642 resolution, cropping and binning:
- * This sensor supports it all, at least in the feature description.
- * Unfortunately, no combination of appropriate registers settings could make
- * the chip work the intended way. As it works with predefined register lists,
- * some undocumented registers are presumably changed there to achieve their
- * goals.
- * This driver currently only works for resolutions up to 720 lines with a
- * 1:1 scale. Hopefully these restrictions will be removed in the future.
- */
-#define OV5642_MAX_WIDTH       OV5642_SENSOR_SIZE_X
-#define OV5642_MAX_HEIGHT      720
-
-/* default sizes */
-#define OV5642_DEFAULT_WIDTH   1280
-#define OV5642_DEFAULT_HEIGHT  OV5642_MAX_HEIGHT
-
-/* minimum extra blanking */
-#define BLANKING_EXTRA_WIDTH           500
-#define BLANKING_EXTRA_HEIGHT          20
-
-/*
- * the sensor's autoexposure is buggy when setting total_height low.
- * It tries to expose longer than 1 frame period without taking care of it
- * and this leads to weird output. So we set 1000 lines as minimum.
- */
-#define BLANKING_MIN_HEIGHT            1000
-
-struct regval_list {
-       u16 reg_num;
-       u8 value;
-};
-
-static struct regval_list ov5642_default_regs_init[] = {
-       { 0x3103, 0x93 },
-       { 0x3008, 0x82 },
-       { 0x3017, 0x7f },
-       { 0x3018, 0xfc },
-       { 0x3810, 0xc2 },
-       { 0x3615, 0xf0 },
-       { 0x3000, 0x0  },
-       { 0x3001, 0x0  },
-       { 0x3002, 0x0  },
-       { 0x3003, 0x0  },
-       { 0x3004, 0xff },
-       { 0x3030, 0x2b },
-       { 0x3011, 0x8  },
-       { 0x3010, 0x10 },
-       { 0x3604, 0x60 },
-       { 0x3622, 0x60 },
-       { 0x3621, 0x9  },
-       { 0x3709, 0x0  },
-       { 0x4000, 0x21 },
-       { 0x401d, 0x22 },
-       { 0x3600, 0x54 },
-       { 0x3605, 0x4  },
-       { 0x3606, 0x3f },
-       { 0x3c01, 0x80 },
-       { 0x300d, 0x22 },
-       { 0x3623, 0x22 },
-       { 0x5000, 0x4f },
-       { 0x5020, 0x4  },
-       { 0x5181, 0x79 },
-       { 0x5182, 0x0  },
-       { 0x5185, 0x22 },
-       { 0x5197, 0x1  },
-       { 0x5500, 0xa  },
-       { 0x5504, 0x0  },
-       { 0x5505, 0x7f },
-       { 0x5080, 0x8  },
-       { 0x300e, 0x18 },
-       { 0x4610, 0x0  },
-       { 0x471d, 0x5  },
-       { 0x4708, 0x6  },
-       { 0x370c, 0xa0 },
-       { 0x5687, 0x94 },
-       { 0x501f, 0x0  },
-       { 0x5000, 0x4f },
-       { 0x5001, 0xcf },
-       { 0x4300, 0x30 },
-       { 0x4300, 0x30 },
-       { 0x460b, 0x35 },
-       { 0x471d, 0x0  },
-       { 0x3002, 0xc  },
-       { 0x3002, 0x0  },
-       { 0x4713, 0x3  },
-       { 0x471c, 0x50 },
-       { 0x4721, 0x2  },
-       { 0x4402, 0x90 },
-       { 0x460c, 0x22 },
-       { 0x3815, 0x44 },
-       { 0x3503, 0x7  },
-       { 0x3501, 0x73 },
-       { 0x3502, 0x80 },
-       { 0x350b, 0x0  },
-       { 0x3818, 0xc8 },
-       { 0x3824, 0x11 },
-       { 0x3a00, 0x78 },
-       { 0x3a1a, 0x4  },
-       { 0x3a13, 0x30 },
-       { 0x3a18, 0x0  },
-       { 0x3a19, 0x7c },
-       { 0x3a08, 0x12 },
-       { 0x3a09, 0xc0 },
-       { 0x3a0a, 0xf  },
-       { 0x3a0b, 0xa0 },
-       { 0x350c, 0x7  },
-       { 0x350d, 0xd0 },
-       { 0x3a0d, 0x8  },
-       { 0x3a0e, 0x6  },
-       { 0x3500, 0x0  },
-       { 0x3501, 0x0  },
-       { 0x3502, 0x0  },
-       { 0x350a, 0x0  },
-       { 0x350b, 0x0  },
-       { 0x3503, 0x0  },
-       { 0x3a0f, 0x3c },
-       { 0x3a10, 0x32 },
-       { 0x3a1b, 0x3c },
-       { 0x3a1e, 0x32 },
-       { 0x3a11, 0x80 },
-       { 0x3a1f, 0x20 },
-       { 0x3030, 0x2b },
-       { 0x3a02, 0x0  },
-       { 0x3a03, 0x7d },
-       { 0x3a04, 0x0  },
-       { 0x3a14, 0x0  },
-       { 0x3a15, 0x7d },
-       { 0x3a16, 0x0  },
-       { 0x3a00, 0x78 },
-       { 0x3a08, 0x9  },
-       { 0x3a09, 0x60 },
-       { 0x3a0a, 0x7  },
-       { 0x3a0b, 0xd0 },
-       { 0x3a0d, 0x10 },
-       { 0x3a0e, 0xd  },
-       { 0x4407, 0x4  },
-       { 0x5193, 0x70 },
-       { 0x589b, 0x0  },
-       { 0x589a, 0xc0 },
-       { 0x401e, 0x20 },
-       { 0x4001, 0x42 },
-       { 0x401c, 0x6  },
-       { 0x3825, 0xac },
-       { 0x3827, 0xc  },
-       { 0x528a, 0x1  },
-       { 0x528b, 0x4  },
-       { 0x528c, 0x8  },
-       { 0x528d, 0x10 },
-       { 0x528e, 0x20 },
-       { 0x528f, 0x28 },
-       { 0x5290, 0x30 },
-       { 0x5292, 0x0  },
-       { 0x5293, 0x1  },
-       { 0x5294, 0x0  },
-       { 0x5295, 0x4  },
-       { 0x5296, 0x0  },
-       { 0x5297, 0x8  },
-       { 0x5298, 0x0  },
-       { 0x5299, 0x10 },
-       { 0x529a, 0x0  },
-       { 0x529b, 0x20 },
-       { 0x529c, 0x0  },
-       { 0x529d, 0x28 },
-       { 0x529e, 0x0  },
-       { 0x529f, 0x30 },
-       { 0x5282, 0x0  },
-       { 0x5300, 0x0  },
-       { 0x5301, 0x20 },
-       { 0x5302, 0x0  },
-       { 0x5303, 0x7c },
-       { 0x530c, 0x0  },
-       { 0x530d, 0xc  },
-       { 0x530e, 0x20 },
-       { 0x530f, 0x80 },
-       { 0x5310, 0x20 },
-       { 0x5311, 0x80 },
-       { 0x5308, 0x20 },
-       { 0x5309, 0x40 },
-       { 0x5304, 0x0  },
-       { 0x5305, 0x30 },
-       { 0x5306, 0x0  },
-       { 0x5307, 0x80 },
-       { 0x5314, 0x8  },
-       { 0x5315, 0x20 },
-       { 0x5319, 0x30 },
-       { 0x5316, 0x10 },
-       { 0x5317, 0x0  },
-       { 0x5318, 0x2  },
-       { 0x5380, 0x1  },
-       { 0x5381, 0x0  },
-       { 0x5382, 0x0  },
-       { 0x5383, 0x4e },
-       { 0x5384, 0x0  },
-       { 0x5385, 0xf  },
-       { 0x5386, 0x0  },
-       { 0x5387, 0x0  },
-       { 0x5388, 0x1  },
-       { 0x5389, 0x15 },
-       { 0x538a, 0x0  },
-       { 0x538b, 0x31 },
-       { 0x538c, 0x0  },
-       { 0x538d, 0x0  },
-       { 0x538e, 0x0  },
-       { 0x538f, 0xf  },
-       { 0x5390, 0x0  },
-       { 0x5391, 0xab },
-       { 0x5392, 0x0  },
-       { 0x5393, 0xa2 },
-       { 0x5394, 0x8  },
-       { 0x5480, 0x14 },
-       { 0x5481, 0x21 },
-       { 0x5482, 0x36 },
-       { 0x5483, 0x57 },
-       { 0x5484, 0x65 },
-       { 0x5485, 0x71 },
-       { 0x5486, 0x7d },
-       { 0x5487, 0x87 },
-       { 0x5488, 0x91 },
-       { 0x5489, 0x9a },
-       { 0x548a, 0xaa },
-       { 0x548b, 0xb8 },
-       { 0x548c, 0xcd },
-       { 0x548d, 0xdd },
-       { 0x548e, 0xea },
-       { 0x548f, 0x1d },
-       { 0x5490, 0x5  },
-       { 0x5491, 0x0  },
-       { 0x5492, 0x4  },
-       { 0x5493, 0x20 },
-       { 0x5494, 0x3  },
-       { 0x5495, 0x60 },
-       { 0x5496, 0x2  },
-       { 0x5497, 0xb8 },
-       { 0x5498, 0x2  },
-       { 0x5499, 0x86 },
-       { 0x549a, 0x2  },
-       { 0x549b, 0x5b },
-       { 0x549c, 0x2  },
-       { 0x549d, 0x3b },
-       { 0x549e, 0x2  },
-       { 0x549f, 0x1c },
-       { 0x54a0, 0x2  },
-       { 0x54a1, 0x4  },
-       { 0x54a2, 0x1  },
-       { 0x54a3, 0xed },
-       { 0x54a4, 0x1  },
-       { 0x54a5, 0xc5 },
-       { 0x54a6, 0x1  },
-       { 0x54a7, 0xa5 },
-       { 0x54a8, 0x1  },
-       { 0x54a9, 0x6c },
-       { 0x54aa, 0x1  },
-       { 0x54ab, 0x41 },
-       { 0x54ac, 0x1  },
-       { 0x54ad, 0x20 },
-       { 0x54ae, 0x0  },
-       { 0x54af, 0x16 },
-       { 0x54b0, 0x1  },
-       { 0x54b1, 0x20 },
-       { 0x54b2, 0x0  },
-       { 0x54b3, 0x10 },
-       { 0x54b4, 0x0  },
-       { 0x54b5, 0xf0 },
-       { 0x54b6, 0x0  },
-       { 0x54b7, 0xdf },
-       { 0x5402, 0x3f },
-       { 0x5403, 0x0  },
-       { 0x3406, 0x0  },
-       { 0x5180, 0xff },
-       { 0x5181, 0x52 },
-       { 0x5182, 0x11 },
-       { 0x5183, 0x14 },
-       { 0x5184, 0x25 },
-       { 0x5185, 0x24 },
-       { 0x5186, 0x6  },
-       { 0x5187, 0x8  },
-       { 0x5188, 0x8  },
-       { 0x5189, 0x7c },
-       { 0x518a, 0x60 },
-       { 0x518b, 0xb2 },
-       { 0x518c, 0xb2 },
-       { 0x518d, 0x44 },
-       { 0x518e, 0x3d },
-       { 0x518f, 0x58 },
-       { 0x5190, 0x46 },
-       { 0x5191, 0xf8 },
-       { 0x5192, 0x4  },
-       { 0x5193, 0x70 },
-       { 0x5194, 0xf0 },
-       { 0x5195, 0xf0 },
-       { 0x5196, 0x3  },
-       { 0x5197, 0x1  },
-       { 0x5198, 0x4  },
-       { 0x5199, 0x12 },
-       { 0x519a, 0x4  },
-       { 0x519b, 0x0  },
-       { 0x519c, 0x6  },
-       { 0x519d, 0x82 },
-       { 0x519e, 0x0  },
-       { 0x5025, 0x80 },
-       { 0x3a0f, 0x38 },
-       { 0x3a10, 0x30 },
-       { 0x3a1b, 0x3a },
-       { 0x3a1e, 0x2e },
-       { 0x3a11, 0x60 },
-       { 0x3a1f, 0x10 },
-       { 0x5688, 0xa6 },
-       { 0x5689, 0x6a },
-       { 0x568a, 0xea },
-       { 0x568b, 0xae },
-       { 0x568c, 0xa6 },
-       { 0x568d, 0x6a },
-       { 0x568e, 0x62 },
-       { 0x568f, 0x26 },
-       { 0x5583, 0x40 },
-       { 0x5584, 0x40 },
-       { 0x5580, 0x2  },
-       { 0x5000, 0xcf },
-       { 0x5800, 0x27 },
-       { 0x5801, 0x19 },
-       { 0x5802, 0x12 },
-       { 0x5803, 0xf  },
-       { 0x5804, 0x10 },
-       { 0x5805, 0x15 },
-       { 0x5806, 0x1e },
-       { 0x5807, 0x2f },
-       { 0x5808, 0x15 },
-       { 0x5809, 0xd  },
-       { 0x580a, 0xa  },
-       { 0x580b, 0x9  },
-       { 0x580c, 0xa  },
-       { 0x580d, 0xc  },
-       { 0x580e, 0x12 },
-       { 0x580f, 0x19 },
-       { 0x5810, 0xb  },
-       { 0x5811, 0x7  },
-       { 0x5812, 0x4  },
-       { 0x5813, 0x3  },
-       { 0x5814, 0x3  },
-       { 0x5815, 0x6  },
-       { 0x5816, 0xa  },
-       { 0x5817, 0xf  },
-       { 0x5818, 0xa  },
-       { 0x5819, 0x5  },
-       { 0x581a, 0x1  },
-       { 0x581b, 0x0  },
-       { 0x581c, 0x0  },
-       { 0x581d, 0x3  },
-       { 0x581e, 0x8  },
-       { 0x581f, 0xc  },
-       { 0x5820, 0xa  },
-       { 0x5821, 0x5  },
-       { 0x5822, 0x1  },
-       { 0x5823, 0x0  },
-       { 0x5824, 0x0  },
-       { 0x5825, 0x3  },
-       { 0x5826, 0x8  },
-       { 0x5827, 0xc  },
-       { 0x5828, 0xe  },
-       { 0x5829, 0x8  },
-       { 0x582a, 0x6  },
-       { 0x582b, 0x4  },
-       { 0x582c, 0x5  },
-       { 0x582d, 0x7  },
-       { 0x582e, 0xb  },
-       { 0x582f, 0x12 },
-       { 0x5830, 0x18 },
-       { 0x5831, 0x10 },
-       { 0x5832, 0xc  },
-       { 0x5833, 0xa  },
-       { 0x5834, 0xb  },
-       { 0x5835, 0xe  },
-       { 0x5836, 0x15 },
-       { 0x5837, 0x19 },
-       { 0x5838, 0x32 },
-       { 0x5839, 0x1f },
-       { 0x583a, 0x18 },
-       { 0x583b, 0x16 },
-       { 0x583c, 0x17 },
-       { 0x583d, 0x1e },
-       { 0x583e, 0x26 },
-       { 0x583f, 0x53 },
-       { 0x5840, 0x10 },
-       { 0x5841, 0xf  },
-       { 0x5842, 0xd  },
-       { 0x5843, 0xc  },
-       { 0x5844, 0xe  },
-       { 0x5845, 0x9  },
-       { 0x5846, 0x11 },
-       { 0x5847, 0x10 },
-       { 0x5848, 0x10 },
-       { 0x5849, 0x10 },
-       { 0x584a, 0x10 },
-       { 0x584b, 0xe  },
-       { 0x584c, 0x10 },
-       { 0x584d, 0x10 },
-       { 0x584e, 0x11 },
-       { 0x584f, 0x10 },
-       { 0x5850, 0xf  },
-       { 0x5851, 0xc  },
-       { 0x5852, 0xf  },
-       { 0x5853, 0x10 },
-       { 0x5854, 0x10 },
-       { 0x5855, 0xf  },
-       { 0x5856, 0xe  },
-       { 0x5857, 0xb  },
-       { 0x5858, 0x10 },
-       { 0x5859, 0xd  },
-       { 0x585a, 0xd  },
-       { 0x585b, 0xc  },
-       { 0x585c, 0xc  },
-       { 0x585d, 0xc  },
-       { 0x585e, 0xb  },
-       { 0x585f, 0xc  },
-       { 0x5860, 0xc  },
-       { 0x5861, 0xc  },
-       { 0x5862, 0xd  },
-       { 0x5863, 0x8  },
-       { 0x5864, 0x11 },
-       { 0x5865, 0x18 },
-       { 0x5866, 0x18 },
-       { 0x5867, 0x19 },
-       { 0x5868, 0x17 },
-       { 0x5869, 0x19 },
-       { 0x586a, 0x16 },
-       { 0x586b, 0x13 },
-       { 0x586c, 0x13 },
-       { 0x586d, 0x12 },
-       { 0x586e, 0x13 },
-       { 0x586f, 0x16 },
-       { 0x5870, 0x14 },
-       { 0x5871, 0x12 },
-       { 0x5872, 0x10 },
-       { 0x5873, 0x11 },
-       { 0x5874, 0x11 },
-       { 0x5875, 0x16 },
-       { 0x5876, 0x14 },
-       { 0x5877, 0x11 },
-       { 0x5878, 0x10 },
-       { 0x5879, 0xf  },
-       { 0x587a, 0x10 },
-       { 0x587b, 0x14 },
-       { 0x587c, 0x13 },
-       { 0x587d, 0x12 },
-       { 0x587e, 0x11 },
-       { 0x587f, 0x11 },
-       { 0x5880, 0x12 },
-       { 0x5881, 0x15 },
-       { 0x5882, 0x14 },
-       { 0x5883, 0x15 },
-       { 0x5884, 0x15 },
-       { 0x5885, 0x15 },
-       { 0x5886, 0x13 },
-       { 0x5887, 0x17 },
-       { 0x3710, 0x10 },
-       { 0x3632, 0x51 },
-       { 0x3702, 0x10 },
-       { 0x3703, 0xb2 },
-       { 0x3704, 0x18 },
-       { 0x370b, 0x40 },
-       { 0x370d, 0x3  },
-       { 0x3631, 0x1  },
-       { 0x3632, 0x52 },
-       { 0x3606, 0x24 },
-       { 0x3620, 0x96 },
-       { 0x5785, 0x7  },
-       { 0x3a13, 0x30 },
-       { 0x3600, 0x52 },
-       { 0x3604, 0x48 },
-       { 0x3606, 0x1b },
-       { 0x370d, 0xb  },
-       { 0x370f, 0xc0 },
-       { 0x3709, 0x1  },
-       { 0x3823, 0x0  },
-       { 0x5007, 0x0  },
-       { 0x5009, 0x0  },
-       { 0x5011, 0x0  },
-       { 0x5013, 0x0  },
-       { 0x519e, 0x0  },
-       { 0x5086, 0x0  },
-       { 0x5087, 0x0  },
-       { 0x5088, 0x0  },
-       { 0x5089, 0x0  },
-       { 0x302b, 0x0  },
-       { 0x3503, 0x7  },
-       { 0x3011, 0x8  },
-       { 0x350c, 0x2  },
-       { 0x350d, 0xe4 },
-       { 0x3621, 0xc9 },
-       { 0x370a, 0x81 },
-       { 0xffff, 0xff },
-};
-
-static struct regval_list ov5642_default_regs_finalise[] = {
-       { 0x3810, 0xc2 },
-       { 0x3818, 0xc9 },
-       { 0x381c, 0x10 },
-       { 0x381d, 0xa0 },
-       { 0x381e, 0x5  },
-       { 0x381f, 0xb0 },
-       { 0x3820, 0x0  },
-       { 0x3821, 0x0  },
-       { 0x3824, 0x11 },
-       { 0x3a08, 0x1b },
-       { 0x3a09, 0xc0 },
-       { 0x3a0a, 0x17 },
-       { 0x3a0b, 0x20 },
-       { 0x3a0d, 0x2  },
-       { 0x3a0e, 0x1  },
-       { 0x401c, 0x4  },
-       { 0x5682, 0x5  },
-       { 0x5683, 0x0  },
-       { 0x5686, 0x2  },
-       { 0x5687, 0xcc },
-       { 0x5001, 0x4f },
-       { 0x589b, 0x6  },
-       { 0x589a, 0xc5 },
-       { 0x3503, 0x0  },
-       { 0x460c, 0x20 },
-       { 0x460b, 0x37 },
-       { 0x471c, 0xd0 },
-       { 0x471d, 0x5  },
-       { 0x3815, 0x1  },
-       { 0x3818, 0xc1 },
-       { 0x501f, 0x0  },
-       { 0x5002, 0xe0 },
-       { 0x4300, 0x32 }, /* UYVY */
-       { 0x3002, 0x1c },
-       { 0x4800, 0x14 },
-       { 0x4801, 0xf  },
-       { 0x3007, 0x3b },
-       { 0x300e, 0x4  },
-       { 0x4803, 0x50 },
-       { 0x3815, 0x1  },
-       { 0x4713, 0x2  },
-       { 0x4842, 0x1  },
-       { 0x300f, 0xe  },
-       { 0x3003, 0x3  },
-       { 0x3003, 0x1  },
-       { 0xffff, 0xff },
-};
-
-struct ov5642_datafmt {
-       u32     code;
-       enum v4l2_colorspace            colorspace;
-};
-
-struct ov5642 {
-       struct v4l2_subdev              subdev;
-       const struct ov5642_datafmt     *fmt;
-       struct v4l2_rect                crop_rect;
-       struct v4l2_clk                 *clk;
-
-       /* blanking information */
-       int total_width;
-       int total_height;
-};
-
-static const struct ov5642_datafmt ov5642_colour_fmts[] = {
-       {MEDIA_BUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG},
-};
-
-static struct ov5642 *to_ov5642(const struct i2c_client *client)
-{
-       return container_of(i2c_get_clientdata(client), struct ov5642, subdev);
-}
-
-/* Find a data format by a pixel code in an array */
-static const struct ov5642_datafmt
-                       *ov5642_find_datafmt(u32 code)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(ov5642_colour_fmts); i++)
-               if (ov5642_colour_fmts[i].code == code)
-                       return ov5642_colour_fmts + i;
-
-       return NULL;
-}
-
-static int reg_read(struct i2c_client *client, u16 reg, u8 *val)
-{
-       int ret;
-       /* We have 16-bit i2c addresses - care for endianness */
-       unsigned char data[2] = { reg >> 8, reg & 0xff };
-
-       ret = i2c_master_send(client, data, 2);
-       if (ret < 2) {
-               dev_err(&client->dev, "%s: i2c read error, reg: %x\n",
-                       __func__, reg);
-               return ret < 0 ? ret : -EIO;
-       }
-
-       ret = i2c_master_recv(client, val, 1);
-       if (ret < 1) {
-               dev_err(&client->dev, "%s: i2c read error, reg: %x\n",
-                               __func__, reg);
-               return ret < 0 ? ret : -EIO;
-       }
-       return 0;
-}
-
-static int reg_write(struct i2c_client *client, u16 reg, u8 val)
-{
-       int ret;
-       unsigned char data[3] = { reg >> 8, reg & 0xff, val };
-
-       ret = i2c_master_send(client, data, 3);
-       if (ret < 3) {
-               dev_err(&client->dev, "%s: i2c write error, reg: %x\n",
-                       __func__, reg);
-               return ret < 0 ? ret : -EIO;
-       }
-
-       return 0;
-}
-
-/*
- * convenience function to write 16 bit register values that are split up
- * into two consecutive high and low parts
- */
-static int reg_write16(struct i2c_client *client, u16 reg, u16 val16)
-{
-       int ret;
-
-       ret = reg_write(client, reg, val16 >> 8);
-       if (ret)
-               return ret;
-       return reg_write(client, reg + 1, val16 & 0x00ff);
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int ov5642_get_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret;
-       u8 val;
-
-       if (reg->reg & ~0xffff)
-               return -EINVAL;
-
-       reg->size = 1;
-
-       ret = reg_read(client, reg->reg, &val);
-       if (!ret)
-               reg->val = (__u64)val;
-
-       return ret;
-}
-
-static int ov5642_set_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (reg->reg & ~0xffff || reg->val & ~0xff)
-               return -EINVAL;
-
-       return reg_write(client, reg->reg, reg->val);
-}
-#endif
-
-static int ov5642_write_array(struct i2c_client *client,
-                               struct regval_list *vals)
-{
-       while (vals->reg_num != 0xffff || vals->value != 0xff) {
-               int ret = reg_write(client, vals->reg_num, vals->value);
-               if (ret < 0)
-                       return ret;
-               vals++;
-       }
-       dev_dbg(&client->dev, "Register list loaded\n");
-       return 0;
-}
-
-static int ov5642_set_resolution(struct v4l2_subdev *sd)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct ov5642 *priv = to_ov5642(client);
-       int width = priv->crop_rect.width;
-       int height = priv->crop_rect.height;
-       int total_width = priv->total_width;
-       int total_height = priv->total_height;
-       int start_x = (OV5642_SENSOR_SIZE_X - width) / 2;
-       int start_y = (OV5642_SENSOR_SIZE_Y - height) / 2;
-       int ret;
-
-       /*
-        * This should set the starting point for cropping.
-        * Doesn't work so far.
-        */
-       ret = reg_write16(client, REG_WINDOW_START_X_HIGH, start_x);
-       if (!ret)
-               ret = reg_write16(client, REG_WINDOW_START_Y_HIGH, start_y);
-       if (!ret) {
-               priv->crop_rect.left = start_x;
-               priv->crop_rect.top = start_y;
-       }
-
-       if (!ret)
-               ret = reg_write16(client, REG_WINDOW_WIDTH_HIGH, width);
-       if (!ret)
-               ret = reg_write16(client, REG_WINDOW_HEIGHT_HIGH, height);
-       if (ret)
-               return ret;
-       priv->crop_rect.width = width;
-       priv->crop_rect.height = height;
-
-       /* Set the output window size. Only 1:1 scale is supported so far. */
-       ret = reg_write16(client, REG_OUT_WIDTH_HIGH, width);
-       if (!ret)
-               ret = reg_write16(client, REG_OUT_HEIGHT_HIGH, height);
-
-       /* Total width = output size + blanking */
-       if (!ret)
-               ret = reg_write16(client, REG_OUT_TOTAL_WIDTH_HIGH, total_width);
-       if (!ret)
-               ret = reg_write16(client, REG_OUT_TOTAL_HEIGHT_HIGH, total_height);
-
-       /* Sets the window for AWB calculations */
-       if (!ret)
-               ret = reg_write16(client, REG_AVG_WINDOW_END_X_HIGH, width);
-       if (!ret)
-               ret = reg_write16(client, REG_AVG_WINDOW_END_Y_HIGH, height);
-
-       return ret;
-}
-
-static int ov5642_set_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_format *format)
-{
-       struct v4l2_mbus_framefmt *mf = &format->format;
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct ov5642 *priv = to_ov5642(client);
-       const struct ov5642_datafmt *fmt = ov5642_find_datafmt(mf->code);
-
-       if (format->pad)
-               return -EINVAL;
-
-       mf->width = priv->crop_rect.width;
-       mf->height = priv->crop_rect.height;
-
-       if (!fmt) {
-               if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
-                       return -EINVAL;
-               mf->code        = ov5642_colour_fmts[0].code;
-               mf->colorspace  = ov5642_colour_fmts[0].colorspace;
-       }
-
-       mf->field       = V4L2_FIELD_NONE;
-
-       if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
-               priv->fmt = fmt;
-       else
-               cfg->try_fmt = *mf;
-       return 0;
-}
-
-static int ov5642_get_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_format *format)
-{
-       struct v4l2_mbus_framefmt *mf = &format->format;
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct ov5642 *priv = to_ov5642(client);
-
-       const struct ov5642_datafmt *fmt = priv->fmt;
-
-       if (format->pad)
-               return -EINVAL;
-
-       mf->code        = fmt->code;
-       mf->colorspace  = fmt->colorspace;
-       mf->width       = priv->crop_rect.width;
-       mf->height      = priv->crop_rect.height;
-       mf->field       = V4L2_FIELD_NONE;
-
-       return 0;
-}
-
-static int ov5642_enum_mbus_code(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_mbus_code_enum *code)
-{
-       if (code->pad || code->index >= ARRAY_SIZE(ov5642_colour_fmts))
-               return -EINVAL;
-
-       code->code = ov5642_colour_fmts[code->index].code;
-       return 0;
-}
-
-static int ov5642_set_selection(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_selection *sel)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct ov5642 *priv = to_ov5642(client);
-       struct v4l2_rect rect = sel->r;
-       int ret;
-
-       if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
-           sel->target != V4L2_SEL_TGT_CROP)
-               return -EINVAL;
-
-       v4l_bound_align_image(&rect.width, 48, OV5642_MAX_WIDTH, 1,
-                             &rect.height, 32, OV5642_MAX_HEIGHT, 1, 0);
-
-       priv->crop_rect.width   = rect.width;
-       priv->crop_rect.height  = rect.height;
-       priv->total_width       = rect.width + BLANKING_EXTRA_WIDTH;
-       priv->total_height      = max_t(int, rect.height +
-                                                       BLANKING_EXTRA_HEIGHT,
-                                                       BLANKING_MIN_HEIGHT);
-       priv->crop_rect.width           = rect.width;
-       priv->crop_rect.height          = rect.height;
-
-       ret = ov5642_write_array(client, ov5642_default_regs_init);
-       if (!ret)
-               ret = ov5642_set_resolution(sd);
-       if (!ret)
-               ret = ov5642_write_array(client, ov5642_default_regs_finalise);
-
-       return ret;
-}
-
-static int ov5642_get_selection(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_selection *sel)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct ov5642 *priv = to_ov5642(client);
-
-       if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
-               return -EINVAL;
-
-       switch (sel->target) {
-       case V4L2_SEL_TGT_CROP_BOUNDS:
-               sel->r.left = 0;
-               sel->r.top = 0;
-               sel->r.width = OV5642_MAX_WIDTH;
-               sel->r.height = OV5642_MAX_HEIGHT;
-               return 0;
-       case V4L2_SEL_TGT_CROP:
-               sel->r = priv->crop_rect;
-               return 0;
-       default:
-               return -EINVAL;
-       }
-}
-
-static int ov5642_g_mbus_config(struct v4l2_subdev *sd,
-                               struct v4l2_mbus_config *cfg)
-{
-       cfg->type = V4L2_MBUS_CSI2_DPHY;
-       cfg->flags = V4L2_MBUS_CSI2_2_LANE | V4L2_MBUS_CSI2_CHANNEL_0 |
-                                       V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
-
-       return 0;
-}
-
-static int ov5642_s_power(struct v4l2_subdev *sd, int on)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
-       struct ov5642 *priv = to_ov5642(client);
-       int ret;
-
-       if (!on)
-               return soc_camera_power_off(&client->dev, ssdd, priv->clk);
-
-       ret = soc_camera_power_on(&client->dev, ssdd, priv->clk);
-       if (ret < 0)
-               return ret;
-
-       ret = ov5642_write_array(client, ov5642_default_regs_init);
-       if (!ret)
-               ret = ov5642_set_resolution(sd);
-       if (!ret)
-               ret = ov5642_write_array(client, ov5642_default_regs_finalise);
-
-       return ret;
-}
-
-static const struct v4l2_subdev_video_ops ov5642_subdev_video_ops = {
-       .g_mbus_config  = ov5642_g_mbus_config,
-};
-
-static const struct v4l2_subdev_pad_ops ov5642_subdev_pad_ops = {
-       .enum_mbus_code = ov5642_enum_mbus_code,
-       .get_selection  = ov5642_get_selection,
-       .set_selection  = ov5642_set_selection,
-       .get_fmt        = ov5642_get_fmt,
-       .set_fmt        = ov5642_set_fmt,
-};
-
-static const struct v4l2_subdev_core_ops ov5642_subdev_core_ops = {
-       .s_power        = ov5642_s_power,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       .g_register     = ov5642_get_register,
-       .s_register     = ov5642_set_register,
-#endif
-};
-
-static const struct v4l2_subdev_ops ov5642_subdev_ops = {
-       .core   = &ov5642_subdev_core_ops,
-       .video  = &ov5642_subdev_video_ops,
-       .pad    = &ov5642_subdev_pad_ops,
-};
-
-static int ov5642_video_probe(struct i2c_client *client)
-{
-       struct v4l2_subdev *subdev = i2c_get_clientdata(client);
-       int ret;
-       u8 id_high, id_low;
-       u16 id;
-
-       ret = ov5642_s_power(subdev, 1);
-       if (ret < 0)
-               return ret;
-
-       /* Read sensor Model ID */
-       ret = reg_read(client, REG_CHIP_ID_HIGH, &id_high);
-       if (ret < 0)
-               goto done;
-
-       id = id_high << 8;
-
-       ret = reg_read(client, REG_CHIP_ID_LOW, &id_low);
-       if (ret < 0)
-               goto done;
-
-       id |= id_low;
-
-       dev_info(&client->dev, "Chip ID 0x%04x detected\n", id);
-
-       if (id != 0x5642) {
-               ret = -ENODEV;
-               goto done;
-       }
-
-       ret = 0;
-
-done:
-       ov5642_s_power(subdev, 0);
-       return ret;
-}
-
-static int ov5642_probe(struct i2c_client *client,
-                       const struct i2c_device_id *did)
-{
-       struct ov5642 *priv;
-       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
-       int ret;
-
-       if (!ssdd) {
-               dev_err(&client->dev, "OV5642: missing platform data!\n");
-               return -EINVAL;
-       }
-
-       priv = devm_kzalloc(&client->dev, sizeof(struct ov5642), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-
-       v4l2_i2c_subdev_init(&priv->subdev, client, &ov5642_subdev_ops);
-
-       priv->fmt               = &ov5642_colour_fmts[0];
-
-       priv->crop_rect.width   = OV5642_DEFAULT_WIDTH;
-       priv->crop_rect.height  = OV5642_DEFAULT_HEIGHT;
-       priv->crop_rect.left    = (OV5642_MAX_WIDTH - OV5642_DEFAULT_WIDTH) / 2;
-       priv->crop_rect.top     = (OV5642_MAX_HEIGHT - OV5642_DEFAULT_HEIGHT) / 2;
-       priv->total_width = OV5642_DEFAULT_WIDTH + BLANKING_EXTRA_WIDTH;
-       priv->total_height = BLANKING_MIN_HEIGHT;
-
-       priv->clk = v4l2_clk_get(&client->dev, "mclk");
-       if (IS_ERR(priv->clk))
-               return PTR_ERR(priv->clk);
-
-       ret = ov5642_video_probe(client);
-       if (ret < 0)
-               v4l2_clk_put(priv->clk);
-
-       return ret;
-}
-
-static int ov5642_remove(struct i2c_client *client)
-{
-       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
-       struct ov5642 *priv = to_ov5642(client);
-
-       v4l2_clk_put(priv->clk);
-       if (ssdd->free_bus)
-               ssdd->free_bus(ssdd);
-
-       return 0;
-}
-
-static const struct i2c_device_id ov5642_id[] = {
-       { "ov5642", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, ov5642_id);
-
-#if IS_ENABLED(CONFIG_OF)
-static const struct of_device_id ov5642_of_match[] = {
-       { .compatible = "ovti,ov5642" },
-       { },
-};
-MODULE_DEVICE_TABLE(of, ov5642_of_match);
-#endif
-
-static struct i2c_driver ov5642_i2c_driver = {
-       .driver = {
-               .name = "ov5642",
-               .of_match_table = of_match_ptr(ov5642_of_match),
-       },
-       .probe          = ov5642_probe,
-       .remove         = ov5642_remove,
-       .id_table       = ov5642_id,
-};
-
-module_i2c_driver(ov5642_i2c_driver);
-
-MODULE_DESCRIPTION("Omnivision OV5642 Camera driver");
-MODULE_AUTHOR("Bastian Hecht <hechtb@gmail.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/soc_camera/ov772x.c b/drivers/media/i2c/soc_camera/ov772x.c
deleted file mode 100644 (file)
index fafd372..0000000
+++ /dev/null
@@ -1,1123 +0,0 @@
-/*
- * ov772x Camera Driver
- *
- * Copyright (C) 2008 Renesas Solutions Corp.
- * Kuninori Morimoto <morimoto.kuninori@renesas.com>
- *
- * Based on ov7670 and soc_camera_platform driver,
- *
- * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
- * Copyright (C) 2008 Magnus Damm
- * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
- *
- * 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.
- */
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/v4l2-mediabus.h>
-#include <linux/videodev2.h>
-
-#include <media/i2c/ov772x.h>
-#include <media/soc_camera.h>
-#include <media/v4l2-clk.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-subdev.h>
-#include <media/v4l2-image-sizes.h>
-
-/*
- * register offset
- */
-#define GAIN        0x00 /* AGC - Gain control gain setting */
-#define BLUE        0x01 /* AWB - Blue channel gain setting */
-#define RED         0x02 /* AWB - Red   channel gain setting */
-#define GREEN       0x03 /* AWB - Green channel gain setting */
-#define COM1        0x04 /* Common control 1 */
-#define BAVG        0x05 /* U/B Average Level */
-#define GAVG        0x06 /* Y/Gb Average Level */
-#define RAVG        0x07 /* V/R Average Level */
-#define AECH        0x08 /* Exposure Value - AEC MSBs */
-#define COM2        0x09 /* Common control 2 */
-#define PID         0x0A /* Product ID Number MSB */
-#define VER         0x0B /* Product ID Number LSB */
-#define COM3        0x0C /* Common control 3 */
-#define COM4        0x0D /* Common control 4 */
-#define COM5        0x0E /* Common control 5 */
-#define COM6        0x0F /* Common control 6 */
-#define AEC         0x10 /* Exposure Value */
-#define CLKRC       0x11 /* Internal clock */
-#define COM7        0x12 /* Common control 7 */
-#define COM8        0x13 /* Common control 8 */
-#define COM9        0x14 /* Common control 9 */
-#define COM10       0x15 /* Common control 10 */
-#define REG16       0x16 /* Register 16 */
-#define HSTART      0x17 /* Horizontal sensor size */
-#define HSIZE       0x18 /* Horizontal frame (HREF column) end high 8-bit */
-#define VSTART      0x19 /* Vertical frame (row) start high 8-bit */
-#define VSIZE       0x1A /* Vertical sensor size */
-#define PSHFT       0x1B /* Data format - pixel delay select */
-#define MIDH        0x1C /* Manufacturer ID byte - high */
-#define MIDL        0x1D /* Manufacturer ID byte - low  */
-#define LAEC        0x1F /* Fine AEC value */
-#define COM11       0x20 /* Common control 11 */
-#define BDBASE      0x22 /* Banding filter Minimum AEC value */
-#define DBSTEP      0x23 /* Banding filter Maximum Setp */
-#define AEW         0x24 /* AGC/AEC - Stable operating region (upper limit) */
-#define AEB         0x25 /* AGC/AEC - Stable operating region (lower limit) */
-#define VPT         0x26 /* AGC/AEC Fast mode operating region */
-#define REG28       0x28 /* Register 28 */
-#define HOUTSIZE    0x29 /* Horizontal data output size MSBs */
-#define EXHCH       0x2A /* Dummy pixel insert MSB */
-#define EXHCL       0x2B /* Dummy pixel insert LSB */
-#define VOUTSIZE    0x2C /* Vertical data output size MSBs */
-#define ADVFL       0x2D /* LSB of insert dummy lines in Vertical direction */
-#define ADVFH       0x2E /* MSG of insert dummy lines in Vertical direction */
-#define YAVE        0x2F /* Y/G Channel Average value */
-#define LUMHTH      0x30 /* Histogram AEC/AGC Luminance high level threshold */
-#define LUMLTH      0x31 /* Histogram AEC/AGC Luminance low  level threshold */
-#define HREF        0x32 /* Image start and size control */
-#define DM_LNL      0x33 /* Dummy line low  8 bits */
-#define DM_LNH      0x34 /* Dummy line high 8 bits */
-#define ADOFF_B     0x35 /* AD offset compensation value for B  channel */
-#define ADOFF_R     0x36 /* AD offset compensation value for R  channel */
-#define ADOFF_GB    0x37 /* AD offset compensation value for Gb channel */
-#define ADOFF_GR    0x38 /* AD offset compensation value for Gr channel */
-#define OFF_B       0x39 /* Analog process B  channel offset value */
-#define OFF_R       0x3A /* Analog process R  channel offset value */
-#define OFF_GB      0x3B /* Analog process Gb channel offset value */
-#define OFF_GR      0x3C /* Analog process Gr channel offset value */
-#define COM12       0x3D /* Common control 12 */
-#define COM13       0x3E /* Common control 13 */
-#define COM14       0x3F /* Common control 14 */
-#define COM15       0x40 /* Common control 15*/
-#define COM16       0x41 /* Common control 16 */
-#define TGT_B       0x42 /* BLC blue channel target value */
-#define TGT_R       0x43 /* BLC red  channel target value */
-#define TGT_GB      0x44 /* BLC Gb   channel target value */
-#define TGT_GR      0x45 /* BLC Gr   channel target value */
-/* for ov7720 */
-#define LCC0        0x46 /* Lens correction control 0 */
-#define LCC1        0x47 /* Lens correction option 1 - X coordinate */
-#define LCC2        0x48 /* Lens correction option 2 - Y coordinate */
-#define LCC3        0x49 /* Lens correction option 3 */
-#define LCC4        0x4A /* Lens correction option 4 - radius of the circular */
-#define LCC5        0x4B /* Lens correction option 5 */
-#define LCC6        0x4C /* Lens correction option 6 */
-/* for ov7725 */
-#define LC_CTR      0x46 /* Lens correction control */
-#define LC_XC       0x47 /* X coordinate of lens correction center relative */
-#define LC_YC       0x48 /* Y coordinate of lens correction center relative */
-#define LC_COEF     0x49 /* Lens correction coefficient */
-#define LC_RADI     0x4A /* Lens correction radius */
-#define LC_COEFB    0x4B /* Lens B channel compensation coefficient */
-#define LC_COEFR    0x4C /* Lens R channel compensation coefficient */
-
-#define FIXGAIN     0x4D /* Analog fix gain amplifer */
-#define AREF0       0x4E /* Sensor reference control */
-#define AREF1       0x4F /* Sensor reference current control */
-#define AREF2       0x50 /* Analog reference control */
-#define AREF3       0x51 /* ADC    reference control */
-#define AREF4       0x52 /* ADC    reference control */
-#define AREF5       0x53 /* ADC    reference control */
-#define AREF6       0x54 /* Analog reference control */
-#define AREF7       0x55 /* Analog reference control */
-#define UFIX        0x60 /* U channel fixed value output */
-#define VFIX        0x61 /* V channel fixed value output */
-#define AWBB_BLK    0x62 /* AWB option for advanced AWB */
-#define AWB_CTRL0   0x63 /* AWB control byte 0 */
-#define DSP_CTRL1   0x64 /* DSP control byte 1 */
-#define DSP_CTRL2   0x65 /* DSP control byte 2 */
-#define DSP_CTRL3   0x66 /* DSP control byte 3 */
-#define DSP_CTRL4   0x67 /* DSP control byte 4 */
-#define AWB_BIAS    0x68 /* AWB BLC level clip */
-#define AWB_CTRL1   0x69 /* AWB control  1 */
-#define AWB_CTRL2   0x6A /* AWB control  2 */
-#define AWB_CTRL3   0x6B /* AWB control  3 */
-#define AWB_CTRL4   0x6C /* AWB control  4 */
-#define AWB_CTRL5   0x6D /* AWB control  5 */
-#define AWB_CTRL6   0x6E /* AWB control  6 */
-#define AWB_CTRL7   0x6F /* AWB control  7 */
-#define AWB_CTRL8   0x70 /* AWB control  8 */
-#define AWB_CTRL9   0x71 /* AWB control  9 */
-#define AWB_CTRL10  0x72 /* AWB control 10 */
-#define AWB_CTRL11  0x73 /* AWB control 11 */
-#define AWB_CTRL12  0x74 /* AWB control 12 */
-#define AWB_CTRL13  0x75 /* AWB control 13 */
-#define AWB_CTRL14  0x76 /* AWB control 14 */
-#define AWB_CTRL15  0x77 /* AWB control 15 */
-#define AWB_CTRL16  0x78 /* AWB control 16 */
-#define AWB_CTRL17  0x79 /* AWB control 17 */
-#define AWB_CTRL18  0x7A /* AWB control 18 */
-#define AWB_CTRL19  0x7B /* AWB control 19 */
-#define AWB_CTRL20  0x7C /* AWB control 20 */
-#define AWB_CTRL21  0x7D /* AWB control 21 */
-#define GAM1        0x7E /* Gamma Curve  1st segment input end point */
-#define GAM2        0x7F /* Gamma Curve  2nd segment input end point */
-#define GAM3        0x80 /* Gamma Curve  3rd segment input end point */
-#define GAM4        0x81 /* Gamma Curve  4th segment input end point */
-#define GAM5        0x82 /* Gamma Curve  5th segment input end point */
-#define GAM6        0x83 /* Gamma Curve  6th segment input end point */
-#define GAM7        0x84 /* Gamma Curve  7th segment input end point */
-#define GAM8        0x85 /* Gamma Curve  8th segment input end point */
-#define GAM9        0x86 /* Gamma Curve  9th segment input end point */
-#define GAM10       0x87 /* Gamma Curve 10th segment input end point */
-#define GAM11       0x88 /* Gamma Curve 11th segment input end point */
-#define GAM12       0x89 /* Gamma Curve 12th segment input end point */
-#define GAM13       0x8A /* Gamma Curve 13th segment input end point */
-#define GAM14       0x8B /* Gamma Curve 14th segment input end point */
-#define GAM15       0x8C /* Gamma Curve 15th segment input end point */
-#define SLOP        0x8D /* Gamma curve highest segment slope */
-#define DNSTH       0x8E /* De-noise threshold */
-#define EDGE_STRNGT 0x8F /* Edge strength  control when manual mode */
-#define EDGE_TRSHLD 0x90 /* Edge threshold control when manual mode */
-#define DNSOFF      0x91 /* Auto De-noise threshold control */
-#define EDGE_UPPER  0x92 /* Edge strength upper limit when Auto mode */
-#define EDGE_LOWER  0x93 /* Edge strength lower limit when Auto mode */
-#define MTX1        0x94 /* Matrix coefficient 1 */
-#define MTX2        0x95 /* Matrix coefficient 2 */
-#define MTX3        0x96 /* Matrix coefficient 3 */
-#define MTX4        0x97 /* Matrix coefficient 4 */
-#define MTX5        0x98 /* Matrix coefficient 5 */
-#define MTX6        0x99 /* Matrix coefficient 6 */
-#define MTX_CTRL    0x9A /* Matrix control */
-#define BRIGHT      0x9B /* Brightness control */
-#define CNTRST      0x9C /* Contrast contrast */
-#define CNTRST_CTRL 0x9D /* Contrast contrast center */
-#define UVAD_J0     0x9E /* Auto UV adjust contrast 0 */
-#define UVAD_J1     0x9F /* Auto UV adjust contrast 1 */
-#define SCAL0       0xA0 /* Scaling control 0 */
-#define SCAL1       0xA1 /* Scaling control 1 */
-#define SCAL2       0xA2 /* Scaling control 2 */
-#define FIFODLYM    0xA3 /* FIFO manual mode delay control */
-#define FIFODLYA    0xA4 /* FIFO auto   mode delay control */
-#define SDE         0xA6 /* Special digital effect control */
-#define USAT        0xA7 /* U component saturation control */
-#define VSAT        0xA8 /* V component saturation control */
-/* for ov7720 */
-#define HUE0        0xA9 /* Hue control 0 */
-#define HUE1        0xAA /* Hue control 1 */
-/* for ov7725 */
-#define HUECOS      0xA9 /* Cosine value */
-#define HUESIN      0xAA /* Sine value */
-
-#define SIGN        0xAB /* Sign bit for Hue and contrast */
-#define DSPAUTO     0xAC /* DSP auto function ON/OFF control */
-
-/*
- * register detail
- */
-
-/* COM2 */
-#define SOFT_SLEEP_MODE 0x10   /* Soft sleep mode */
-                               /* Output drive capability */
-#define OCAP_1x         0x00   /* 1x */
-#define OCAP_2x         0x01   /* 2x */
-#define OCAP_3x         0x02   /* 3x */
-#define OCAP_4x         0x03   /* 4x */
-
-/* COM3 */
-#define SWAP_MASK       (SWAP_RGB | SWAP_YUV | SWAP_ML)
-#define IMG_MASK        (VFLIP_IMG | HFLIP_IMG)
-
-#define VFLIP_IMG       0x80   /* Vertical flip image ON/OFF selection */
-#define HFLIP_IMG       0x40   /* Horizontal mirror image ON/OFF selection */
-#define SWAP_RGB        0x20   /* Swap B/R  output sequence in RGB mode */
-#define SWAP_YUV        0x10   /* Swap Y/UV output sequence in YUV mode */
-#define SWAP_ML         0x08   /* Swap output MSB/LSB */
-                               /* Tri-state option for output clock */
-#define NOTRI_CLOCK     0x04   /*   0: Tri-state    at this period */
-                               /*   1: No tri-state at this period */
-                               /* Tri-state option for output data */
-#define NOTRI_DATA      0x02   /*   0: Tri-state    at this period */
-                               /*   1: No tri-state at this period */
-#define SCOLOR_TEST     0x01   /* Sensor color bar test pattern */
-
-/* COM4 */
-                               /* PLL frequency control */
-#define PLL_BYPASS      0x00   /*  00: Bypass PLL */
-#define PLL_4x          0x40   /*  01: PLL 4x */
-#define PLL_6x          0x80   /*  10: PLL 6x */
-#define PLL_8x          0xc0   /*  11: PLL 8x */
-                               /* AEC evaluate window */
-#define AEC_FULL        0x00   /*  00: Full window */
-#define AEC_1p2         0x10   /*  01: 1/2  window */
-#define AEC_1p4         0x20   /*  10: 1/4  window */
-#define AEC_2p3         0x30   /*  11: Low 2/3 window */
-
-/* COM5 */
-#define AFR_ON_OFF      0x80   /* Auto frame rate control ON/OFF selection */
-#define AFR_SPPED       0x40   /* Auto frame rate control speed selection */
-                               /* Auto frame rate max rate control */
-#define AFR_NO_RATE     0x00   /*     No  reduction of frame rate */
-#define AFR_1p2         0x10   /*     Max reduction to 1/2 frame rate */
-#define AFR_1p4         0x20   /*     Max reduction to 1/4 frame rate */
-#define AFR_1p8         0x30   /* Max reduction to 1/8 frame rate */
-                               /* Auto frame rate active point control */
-#define AF_2x           0x00   /*     Add frame when AGC reaches  2x gain */
-#define AF_4x           0x04   /*     Add frame when AGC reaches  4x gain */
-#define AF_8x           0x08   /*     Add frame when AGC reaches  8x gain */
-#define AF_16x          0x0c   /* Add frame when AGC reaches 16x gain */
-                               /* AEC max step control */
-#define AEC_NO_LIMIT    0x01   /*   0 : AEC incease step has limit */
-                               /*   1 : No limit to AEC increase step */
-
-/* COM7 */
-                               /* SCCB Register Reset */
-#define SCCB_RESET      0x80   /*   0 : No change */
-                               /*   1 : Resets all registers to default */
-                               /* Resolution selection */
-#define SLCT_MASK       0x40   /*   Mask of VGA or QVGA */
-#define SLCT_VGA        0x00   /*   0 : VGA */
-#define SLCT_QVGA       0x40   /*   1 : QVGA */
-#define ITU656_ON_OFF   0x20   /* ITU656 protocol ON/OFF selection */
-#define SENSOR_RAW     0x10    /* Sensor RAW */
-                               /* RGB output format control */
-#define FMT_MASK        0x0c   /*      Mask of color format */
-#define FMT_GBR422      0x00   /*      00 : GBR 4:2:2 */
-#define FMT_RGB565      0x04   /*      01 : RGB 565 */
-#define FMT_RGB555      0x08   /*      10 : RGB 555 */
-#define FMT_RGB444      0x0c   /* 11 : RGB 444 */
-                               /* Output format control */
-#define OFMT_MASK       0x03    /*      Mask of output format */
-#define OFMT_YUV        0x00   /*      00 : YUV */
-#define OFMT_P_BRAW     0x01   /*      01 : Processed Bayer RAW */
-#define OFMT_RGB        0x02   /*      10 : RGB */
-#define OFMT_BRAW       0x03   /* 11 : Bayer RAW */
-
-/* COM8 */
-#define FAST_ALGO       0x80   /* Enable fast AGC/AEC algorithm */
-                               /* AEC Setp size limit */
-#define UNLMT_STEP      0x40   /*   0 : Step size is limited */
-                               /*   1 : Unlimited step size */
-#define BNDF_ON_OFF     0x20   /* Banding filter ON/OFF */
-#define AEC_BND         0x10   /* Enable AEC below banding value */
-#define AEC_ON_OFF      0x08   /* Fine AEC ON/OFF control */
-#define AGC_ON          0x04   /* AGC Enable */
-#define AWB_ON          0x02   /* AWB Enable */
-#define AEC_ON          0x01   /* AEC Enable */
-
-/* COM9 */
-#define BASE_AECAGC     0x80   /* Histogram or average based AEC/AGC */
-                               /* Automatic gain ceiling - maximum AGC value */
-#define GAIN_2x         0x00   /*    000 :   2x */
-#define GAIN_4x         0x10   /*    001 :   4x */
-#define GAIN_8x         0x20   /*    010 :   8x */
-#define GAIN_16x        0x30   /*    011 :  16x */
-#define GAIN_32x        0x40   /*    100 :  32x */
-#define GAIN_64x        0x50   /* 101 :  64x */
-#define GAIN_128x       0x60   /* 110 : 128x */
-#define DROP_VSYNC      0x04   /* Drop VSYNC output of corrupt frame */
-#define DROP_HREF       0x02   /* Drop HREF  output of corrupt frame */
-
-/* COM11 */
-#define SGLF_ON_OFF     0x02   /* Single frame ON/OFF selection */
-#define SGLF_TRIG       0x01   /* Single frame transfer trigger */
-
-/* HREF */
-#define HREF_VSTART_SHIFT      6       /* VSTART LSB */
-#define HREF_HSTART_SHIFT      4       /* HSTART 2 LSBs */
-#define HREF_VSIZE_SHIFT       2       /* VSIZE LSB */
-#define HREF_HSIZE_SHIFT       0       /* HSIZE 2 LSBs */
-
-/* EXHCH */
-#define EXHCH_VSIZE_SHIFT      2       /* VOUTSIZE LSB */
-#define EXHCH_HSIZE_SHIFT      0       /* HOUTSIZE 2 LSBs */
-
-/* DSP_CTRL1 */
-#define FIFO_ON         0x80   /* FIFO enable/disable selection */
-#define UV_ON_OFF       0x40   /* UV adjust function ON/OFF selection */
-#define YUV444_2_422    0x20   /* YUV444 to 422 UV channel option selection */
-#define CLR_MTRX_ON_OFF 0x10   /* Color matrix ON/OFF selection */
-#define INTPLT_ON_OFF   0x08   /* Interpolation ON/OFF selection */
-#define GMM_ON_OFF      0x04   /* Gamma function ON/OFF selection */
-#define AUTO_BLK_ON_OFF 0x02   /* Black defect auto correction ON/OFF */
-#define AUTO_WHT_ON_OFF 0x01   /* White define auto correction ON/OFF */
-
-/* DSP_CTRL3 */
-#define UV_MASK         0x80   /* UV output sequence option */
-#define UV_ON           0x80   /*   ON */
-#define UV_OFF          0x00   /*   OFF */
-#define CBAR_MASK       0x20   /* DSP Color bar mask */
-#define CBAR_ON         0x20   /*   ON */
-#define CBAR_OFF        0x00   /*   OFF */
-
-/* DSP_CTRL4 */
-#define DSP_OFMT_YUV   0x00
-#define DSP_OFMT_RGB   0x00
-#define DSP_OFMT_RAW8  0x02
-#define DSP_OFMT_RAW10 0x03
-
-/* DSPAUTO (DSP Auto Function ON/OFF Control) */
-#define AWB_ACTRL       0x80 /* AWB auto threshold control */
-#define DENOISE_ACTRL   0x40 /* De-noise auto threshold control */
-#define EDGE_ACTRL      0x20 /* Edge enhancement auto strength control */
-#define UV_ACTRL        0x10 /* UV adjust auto slope control */
-#define SCAL0_ACTRL     0x08 /* Auto scaling factor control */
-#define SCAL1_2_ACTRL   0x04 /* Auto scaling factor control */
-
-#define OV772X_MAX_WIDTH       VGA_WIDTH
-#define OV772X_MAX_HEIGHT      VGA_HEIGHT
-
-/*
- * ID
- */
-#define OV7720  0x7720
-#define OV7725  0x7721
-#define VERSION(pid, ver) ((pid<<8)|(ver&0xFF))
-
-/*
- * struct
- */
-
-struct ov772x_color_format {
-       u32 code;
-       enum v4l2_colorspace colorspace;
-       u8 dsp3;
-       u8 dsp4;
-       u8 com3;
-       u8 com7;
-};
-
-struct ov772x_win_size {
-       char                     *name;
-       unsigned char             com7_bit;
-       struct v4l2_rect          rect;
-};
-
-struct ov772x_priv {
-       struct v4l2_subdev                subdev;
-       struct v4l2_ctrl_handler          hdl;
-       struct v4l2_clk                  *clk;
-       struct ov772x_camera_info        *info;
-       const struct ov772x_color_format *cfmt;
-       const struct ov772x_win_size     *win;
-       unsigned short                    flag_vflip:1;
-       unsigned short                    flag_hflip:1;
-       /* band_filter = COM8[5] ? 256 - BDBASE : 0 */
-       unsigned short                    band_filter;
-};
-
-/*
- * supported color format list
- */
-static const struct ov772x_color_format ov772x_cfmts[] = {
-       {
-               .code           = MEDIA_BUS_FMT_YUYV8_2X8,
-               .colorspace     = V4L2_COLORSPACE_JPEG,
-               .dsp3           = 0x0,
-               .dsp4           = DSP_OFMT_YUV,
-               .com3           = SWAP_YUV,
-               .com7           = OFMT_YUV,
-       },
-       {
-               .code           = MEDIA_BUS_FMT_YVYU8_2X8,
-               .colorspace     = V4L2_COLORSPACE_JPEG,
-               .dsp3           = UV_ON,
-               .dsp4           = DSP_OFMT_YUV,
-               .com3           = SWAP_YUV,
-               .com7           = OFMT_YUV,
-       },
-       {
-               .code           = MEDIA_BUS_FMT_UYVY8_2X8,
-               .colorspace     = V4L2_COLORSPACE_JPEG,
-               .dsp3           = 0x0,
-               .dsp4           = DSP_OFMT_YUV,
-               .com3           = 0x0,
-               .com7           = OFMT_YUV,
-       },
-       {
-               .code           = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE,
-               .colorspace     = V4L2_COLORSPACE_SRGB,
-               .dsp3           = 0x0,
-               .dsp4           = DSP_OFMT_YUV,
-               .com3           = SWAP_RGB,
-               .com7           = FMT_RGB555 | OFMT_RGB,
-       },
-       {
-               .code           = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE,
-               .colorspace     = V4L2_COLORSPACE_SRGB,
-               .dsp3           = 0x0,
-               .dsp4           = DSP_OFMT_YUV,
-               .com3           = 0x0,
-               .com7           = FMT_RGB555 | OFMT_RGB,
-       },
-       {
-               .code           = MEDIA_BUS_FMT_RGB565_2X8_LE,
-               .colorspace     = V4L2_COLORSPACE_SRGB,
-               .dsp3           = 0x0,
-               .dsp4           = DSP_OFMT_YUV,
-               .com3           = SWAP_RGB,
-               .com7           = FMT_RGB565 | OFMT_RGB,
-       },
-       {
-               .code           = MEDIA_BUS_FMT_RGB565_2X8_BE,
-               .colorspace     = V4L2_COLORSPACE_SRGB,
-               .dsp3           = 0x0,
-               .dsp4           = DSP_OFMT_YUV,
-               .com3           = 0x0,
-               .com7           = FMT_RGB565 | OFMT_RGB,
-       },
-       {
-               /* Setting DSP4 to DSP_OFMT_RAW8 still gives 10-bit output,
-                * regardless of the COM7 value. We can thus only support 10-bit
-                * Bayer until someone figures it out.
-                */
-               .code           = MEDIA_BUS_FMT_SBGGR10_1X10,
-               .colorspace     = V4L2_COLORSPACE_SRGB,
-               .dsp3           = 0x0,
-               .dsp4           = DSP_OFMT_RAW10,
-               .com3           = 0x0,
-               .com7           = SENSOR_RAW | OFMT_BRAW,
-       },
-};
-
-
-/*
- * window size list
- */
-
-static const struct ov772x_win_size ov772x_win_sizes[] = {
-       {
-               .name     = "VGA",
-               .com7_bit = SLCT_VGA,
-               .rect = {
-                       .left = 140,
-                       .top = 14,
-                       .width = VGA_WIDTH,
-                       .height = VGA_HEIGHT,
-               },
-       }, {
-               .name     = "QVGA",
-               .com7_bit = SLCT_QVGA,
-               .rect = {
-                       .left = 252,
-                       .top = 6,
-                       .width = QVGA_WIDTH,
-                       .height = QVGA_HEIGHT,
-               },
-       },
-};
-
-/*
- * general function
- */
-
-static struct ov772x_priv *to_ov772x(struct v4l2_subdev *sd)
-{
-       return container_of(sd, struct ov772x_priv, subdev);
-}
-
-static inline int ov772x_read(struct i2c_client *client, u8 addr)
-{
-       return i2c_smbus_read_byte_data(client, addr);
-}
-
-static inline int ov772x_write(struct i2c_client *client, u8 addr, u8 value)
-{
-       return i2c_smbus_write_byte_data(client, addr, value);
-}
-
-static int ov772x_mask_set(struct i2c_client *client, u8  command, u8  mask,
-                          u8  set)
-{
-       s32 val = ov772x_read(client, command);
-       if (val < 0)
-               return val;
-
-       val &= ~mask;
-       val |= set & mask;
-
-       return ov772x_write(client, command, val);
-}
-
-static int ov772x_reset(struct i2c_client *client)
-{
-       int ret;
-
-       ret = ov772x_write(client, COM7, SCCB_RESET);
-       if (ret < 0)
-               return ret;
-
-       msleep(1);
-
-       return ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE);
-}
-
-/*
- * soc_camera_ops function
- */
-
-static int ov772x_s_stream(struct v4l2_subdev *sd, int enable)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct ov772x_priv *priv = to_ov772x(sd);
-
-       if (!enable) {
-               ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE);
-               return 0;
-       }
-
-       ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, 0);
-
-       dev_dbg(&client->dev, "format %d, win %s\n",
-               priv->cfmt->code, priv->win->name);
-
-       return 0;
-}
-
-static int ov772x_s_ctrl(struct v4l2_ctrl *ctrl)
-{
-       struct ov772x_priv *priv = container_of(ctrl->handler,
-                                               struct ov772x_priv, hdl);
-       struct v4l2_subdev *sd = &priv->subdev;
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret = 0;
-       u8 val;
-
-       switch (ctrl->id) {
-       case V4L2_CID_VFLIP:
-               val = ctrl->val ? VFLIP_IMG : 0x00;
-               priv->flag_vflip = ctrl->val;
-               if (priv->info->flags & OV772X_FLAG_VFLIP)
-                       val ^= VFLIP_IMG;
-               return ov772x_mask_set(client, COM3, VFLIP_IMG, val);
-       case V4L2_CID_HFLIP:
-               val = ctrl->val ? HFLIP_IMG : 0x00;
-               priv->flag_hflip = ctrl->val;
-               if (priv->info->flags & OV772X_FLAG_HFLIP)
-                       val ^= HFLIP_IMG;
-               return ov772x_mask_set(client, COM3, HFLIP_IMG, val);
-       case V4L2_CID_BAND_STOP_FILTER:
-               if (!ctrl->val) {
-                       /* Switch the filter off, it is on now */
-                       ret = ov772x_mask_set(client, BDBASE, 0xff, 0xff);
-                       if (!ret)
-                               ret = ov772x_mask_set(client, COM8,
-                                                     BNDF_ON_OFF, 0);
-               } else {
-                       /* Switch the filter on, set AEC low limit */
-                       val = 256 - ctrl->val;
-                       ret = ov772x_mask_set(client, COM8,
-                                             BNDF_ON_OFF, BNDF_ON_OFF);
-                       if (!ret)
-                               ret = ov772x_mask_set(client, BDBASE,
-                                                     0xff, val);
-               }
-               if (!ret)
-                       priv->band_filter = ctrl->val;
-               return ret;
-       }
-
-       return -EINVAL;
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int ov772x_g_register(struct v4l2_subdev *sd,
-                            struct v4l2_dbg_register *reg)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret;
-
-       reg->size = 1;
-       if (reg->reg > 0xff)
-               return -EINVAL;
-
-       ret = ov772x_read(client, reg->reg);
-       if (ret < 0)
-               return ret;
-
-       reg->val = (__u64)ret;
-
-       return 0;
-}
-
-static int ov772x_s_register(struct v4l2_subdev *sd,
-                            const struct v4l2_dbg_register *reg)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (reg->reg > 0xff ||
-           reg->val > 0xff)
-               return -EINVAL;
-
-       return ov772x_write(client, reg->reg, reg->val);
-}
-#endif
-
-static int ov772x_s_power(struct v4l2_subdev *sd, int on)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
-       struct ov772x_priv *priv = to_ov772x(sd);
-
-       return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
-}
-
-static const struct ov772x_win_size *ov772x_select_win(u32 width, u32 height)
-{
-       const struct ov772x_win_size *win = &ov772x_win_sizes[0];
-       u32 best_diff = UINT_MAX;
-       unsigned int i;
-
-       for (i = 0; i < ARRAY_SIZE(ov772x_win_sizes); ++i) {
-               u32 diff = abs(width - ov772x_win_sizes[i].rect.width)
-                        + abs(height - ov772x_win_sizes[i].rect.height);
-               if (diff < best_diff) {
-                       best_diff = diff;
-                       win = &ov772x_win_sizes[i];
-               }
-       }
-
-       return win;
-}
-
-static void ov772x_select_params(const struct v4l2_mbus_framefmt *mf,
-                                const struct ov772x_color_format **cfmt,
-                                const struct ov772x_win_size **win)
-{
-       unsigned int i;
-
-       /* Select a format. */
-       *cfmt = &ov772x_cfmts[0];
-
-       for (i = 0; i < ARRAY_SIZE(ov772x_cfmts); i++) {
-               if (mf->code == ov772x_cfmts[i].code) {
-                       *cfmt = &ov772x_cfmts[i];
-                       break;
-               }
-       }
-
-       /* Select a window size. */
-       *win = ov772x_select_win(mf->width, mf->height);
-}
-
-static int ov772x_set_params(struct ov772x_priv *priv,
-                            const struct ov772x_color_format *cfmt,
-                            const struct ov772x_win_size *win)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev);
-       int ret;
-       u8  val;
-
-       /*
-        * reset hardware
-        */
-       ov772x_reset(client);
-
-       /*
-        * Edge Ctrl
-        */
-       if (priv->info->edgectrl.strength & OV772X_MANUAL_EDGE_CTRL) {
-
-               /*
-                * Manual Edge Control Mode
-                *
-                * Edge auto strength bit is set by default.
-                * Remove it when manual mode.
-                */
-
-               ret = ov772x_mask_set(client, DSPAUTO, EDGE_ACTRL, 0x00);
-               if (ret < 0)
-                       goto ov772x_set_fmt_error;
-
-               ret = ov772x_mask_set(client,
-                                     EDGE_TRSHLD, OV772X_EDGE_THRESHOLD_MASK,
-                                     priv->info->edgectrl.threshold);
-               if (ret < 0)
-                       goto ov772x_set_fmt_error;
-
-               ret = ov772x_mask_set(client,
-                                     EDGE_STRNGT, OV772X_EDGE_STRENGTH_MASK,
-                                     priv->info->edgectrl.strength);
-               if (ret < 0)
-                       goto ov772x_set_fmt_error;
-
-       } else if (priv->info->edgectrl.upper > priv->info->edgectrl.lower) {
-               /*
-                * Auto Edge Control Mode
-                *
-                * set upper and lower limit
-                */
-               ret = ov772x_mask_set(client,
-                                     EDGE_UPPER, OV772X_EDGE_UPPER_MASK,
-                                     priv->info->edgectrl.upper);
-               if (ret < 0)
-                       goto ov772x_set_fmt_error;
-
-               ret = ov772x_mask_set(client,
-                                     EDGE_LOWER, OV772X_EDGE_LOWER_MASK,
-                                     priv->info->edgectrl.lower);
-               if (ret < 0)
-                       goto ov772x_set_fmt_error;
-       }
-
-       /* Format and window size */
-       ret = ov772x_write(client, HSTART, win->rect.left >> 2);
-       if (ret < 0)
-               goto ov772x_set_fmt_error;
-       ret = ov772x_write(client, HSIZE, win->rect.width >> 2);
-       if (ret < 0)
-               goto ov772x_set_fmt_error;
-       ret = ov772x_write(client, VSTART, win->rect.top >> 1);
-       if (ret < 0)
-               goto ov772x_set_fmt_error;
-       ret = ov772x_write(client, VSIZE, win->rect.height >> 1);
-       if (ret < 0)
-               goto ov772x_set_fmt_error;
-       ret = ov772x_write(client, HOUTSIZE, win->rect.width >> 2);
-       if (ret < 0)
-               goto ov772x_set_fmt_error;
-       ret = ov772x_write(client, VOUTSIZE, win->rect.height >> 1);
-       if (ret < 0)
-               goto ov772x_set_fmt_error;
-       ret = ov772x_write(client, HREF,
-                          ((win->rect.top & 1) << HREF_VSTART_SHIFT) |
-                          ((win->rect.left & 3) << HREF_HSTART_SHIFT) |
-                          ((win->rect.height & 1) << HREF_VSIZE_SHIFT) |
-                          ((win->rect.width & 3) << HREF_HSIZE_SHIFT));
-       if (ret < 0)
-               goto ov772x_set_fmt_error;
-       ret = ov772x_write(client, EXHCH,
-                          ((win->rect.height & 1) << EXHCH_VSIZE_SHIFT) |
-                          ((win->rect.width & 3) << EXHCH_HSIZE_SHIFT));
-       if (ret < 0)
-               goto ov772x_set_fmt_error;
-
-       /*
-        * set DSP_CTRL3
-        */
-       val = cfmt->dsp3;
-       if (val) {
-               ret = ov772x_mask_set(client,
-                                     DSP_CTRL3, UV_MASK, val);
-               if (ret < 0)
-                       goto ov772x_set_fmt_error;
-       }
-
-       /* DSP_CTRL4: AEC reference point and DSP output format. */
-       if (cfmt->dsp4) {
-               ret = ov772x_write(client, DSP_CTRL4, cfmt->dsp4);
-               if (ret < 0)
-                       goto ov772x_set_fmt_error;
-       }
-
-       /*
-        * set COM3
-        */
-       val = cfmt->com3;
-       if (priv->info->flags & OV772X_FLAG_VFLIP)
-               val |= VFLIP_IMG;
-       if (priv->info->flags & OV772X_FLAG_HFLIP)
-               val |= HFLIP_IMG;
-       if (priv->flag_vflip)
-               val ^= VFLIP_IMG;
-       if (priv->flag_hflip)
-               val ^= HFLIP_IMG;
-
-       ret = ov772x_mask_set(client,
-                             COM3, SWAP_MASK | IMG_MASK, val);
-       if (ret < 0)
-               goto ov772x_set_fmt_error;
-
-       /* COM7: Sensor resolution and output format control. */
-       ret = ov772x_write(client, COM7, win->com7_bit | cfmt->com7);
-       if (ret < 0)
-               goto ov772x_set_fmt_error;
-
-       /*
-        * set COM8
-        */
-       if (priv->band_filter) {
-               ret = ov772x_mask_set(client, COM8, BNDF_ON_OFF, BNDF_ON_OFF);
-               if (!ret)
-                       ret = ov772x_mask_set(client, BDBASE,
-                                             0xff, 256 - priv->band_filter);
-               if (ret < 0)
-                       goto ov772x_set_fmt_error;
-       }
-
-       return ret;
-
-ov772x_set_fmt_error:
-
-       ov772x_reset(client);
-
-       return ret;
-}
-
-static int ov772x_get_selection(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_selection *sel)
-{
-       if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
-               return -EINVAL;
-
-       sel->r.left = 0;
-       sel->r.top = 0;
-       switch (sel->target) {
-       case V4L2_SEL_TGT_CROP_BOUNDS:
-               sel->r.width = OV772X_MAX_WIDTH;
-               sel->r.height = OV772X_MAX_HEIGHT;
-               return 0;
-       case V4L2_SEL_TGT_CROP:
-               sel->r.width = VGA_WIDTH;
-               sel->r.height = VGA_HEIGHT;
-               return 0;
-       default:
-               return -EINVAL;
-       }
-}
-
-static int ov772x_get_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_format *format)
-{
-       struct v4l2_mbus_framefmt *mf = &format->format;
-       struct ov772x_priv *priv = to_ov772x(sd);
-
-       if (format->pad)
-               return -EINVAL;
-
-       mf->width       = priv->win->rect.width;
-       mf->height      = priv->win->rect.height;
-       mf->code        = priv->cfmt->code;
-       mf->colorspace  = priv->cfmt->colorspace;
-       mf->field       = V4L2_FIELD_NONE;
-
-       return 0;
-}
-
-static int ov772x_set_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_format *format)
-{
-       struct ov772x_priv *priv = to_ov772x(sd);
-       struct v4l2_mbus_framefmt *mf = &format->format;
-       const struct ov772x_color_format *cfmt;
-       const struct ov772x_win_size *win;
-       int ret;
-
-       if (format->pad)
-               return -EINVAL;
-
-       ov772x_select_params(mf, &cfmt, &win);
-
-       mf->code = cfmt->code;
-       mf->width = win->rect.width;
-       mf->height = win->rect.height;
-       mf->field = V4L2_FIELD_NONE;
-       mf->colorspace = cfmt->colorspace;
-
-       if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
-               cfg->try_fmt = *mf;
-               return 0;
-       }
-
-       ret = ov772x_set_params(priv, cfmt, win);
-       if (ret < 0)
-               return ret;
-
-       priv->win = win;
-       priv->cfmt = cfmt;
-       return 0;
-}
-
-static int ov772x_video_probe(struct ov772x_priv *priv)
-{
-       struct i2c_client  *client = v4l2_get_subdevdata(&priv->subdev);
-       u8                  pid, ver;
-       const char         *devname;
-       int                 ret;
-
-       ret = ov772x_s_power(&priv->subdev, 1);
-       if (ret < 0)
-               return ret;
-
-       /*
-        * check and show product ID and manufacturer ID
-        */
-       pid = ov772x_read(client, PID);
-       ver = ov772x_read(client, VER);
-
-       switch (VERSION(pid, ver)) {
-       case OV7720:
-               devname     = "ov7720";
-               break;
-       case OV7725:
-               devname     = "ov7725";
-               break;
-       default:
-               dev_err(&client->dev,
-                       "Product ID error %x:%x\n", pid, ver);
-               ret = -ENODEV;
-               goto done;
-       }
-
-       dev_info(&client->dev,
-                "%s Product ID %0x:%0x Manufacturer ID %x:%x\n",
-                devname,
-                pid,
-                ver,
-                ov772x_read(client, MIDH),
-                ov772x_read(client, MIDL));
-       ret = v4l2_ctrl_handler_setup(&priv->hdl);
-
-done:
-       ov772x_s_power(&priv->subdev, 0);
-       return ret;
-}
-
-static const struct v4l2_ctrl_ops ov772x_ctrl_ops = {
-       .s_ctrl = ov772x_s_ctrl,
-};
-
-static const struct v4l2_subdev_core_ops ov772x_subdev_core_ops = {
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       .g_register     = ov772x_g_register,
-       .s_register     = ov772x_s_register,
-#endif
-       .s_power        = ov772x_s_power,
-};
-
-static int ov772x_enum_mbus_code(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_mbus_code_enum *code)
-{
-       if (code->pad || code->index >= ARRAY_SIZE(ov772x_cfmts))
-               return -EINVAL;
-
-       code->code = ov772x_cfmts[code->index].code;
-       return 0;
-}
-
-static int ov772x_g_mbus_config(struct v4l2_subdev *sd,
-                               struct v4l2_mbus_config *cfg)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
-
-       cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
-               V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
-               V4L2_MBUS_DATA_ACTIVE_HIGH;
-       cfg->type = V4L2_MBUS_PARALLEL;
-       cfg->flags = soc_camera_apply_board_flags(ssdd, cfg);
-
-       return 0;
-}
-
-static const struct v4l2_subdev_video_ops ov772x_subdev_video_ops = {
-       .s_stream       = ov772x_s_stream,
-       .g_mbus_config  = ov772x_g_mbus_config,
-};
-
-static const struct v4l2_subdev_pad_ops ov772x_subdev_pad_ops = {
-       .enum_mbus_code = ov772x_enum_mbus_code,
-       .get_selection  = ov772x_get_selection,
-       .get_fmt        = ov772x_get_fmt,
-       .set_fmt        = ov772x_set_fmt,
-};
-
-static const struct v4l2_subdev_ops ov772x_subdev_ops = {
-       .core   = &ov772x_subdev_core_ops,
-       .video  = &ov772x_subdev_video_ops,
-       .pad    = &ov772x_subdev_pad_ops,
-};
-
-/*
- * i2c_driver function
- */
-
-static int ov772x_probe(struct i2c_client *client,
-                       const struct i2c_device_id *did)
-{
-       struct ov772x_priv      *priv;
-       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
-       struct i2c_adapter      *adapter = to_i2c_adapter(client->dev.parent);
-       int                     ret;
-
-       if (!ssdd || !ssdd->drv_priv) {
-               dev_err(&client->dev, "OV772X: missing platform data!\n");
-               return -EINVAL;
-       }
-
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
-                                             I2C_FUNC_PROTOCOL_MANGLING)) {
-               dev_err(&adapter->dev,
-                       "I2C-Adapter doesn't support SMBUS_BYTE_DATA or PROTOCOL_MANGLING\n");
-               return -EIO;
-       }
-       client->flags |= I2C_CLIENT_SCCB;
-
-       priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-
-       priv->info = ssdd->drv_priv;
-
-       v4l2_i2c_subdev_init(&priv->subdev, client, &ov772x_subdev_ops);
-       v4l2_ctrl_handler_init(&priv->hdl, 3);
-       v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops,
-                       V4L2_CID_VFLIP, 0, 1, 1, 0);
-       v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops,
-                       V4L2_CID_HFLIP, 0, 1, 1, 0);
-       v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops,
-                       V4L2_CID_BAND_STOP_FILTER, 0, 256, 1, 0);
-       priv->subdev.ctrl_handler = &priv->hdl;
-       if (priv->hdl.error)
-               return priv->hdl.error;
-
-       priv->clk = v4l2_clk_get(&client->dev, "mclk");
-       if (IS_ERR(priv->clk)) {
-               ret = PTR_ERR(priv->clk);
-               goto eclkget;
-       }
-
-       ret = ov772x_video_probe(priv);
-       if (ret < 0) {
-               v4l2_clk_put(priv->clk);
-eclkget:
-               v4l2_ctrl_handler_free(&priv->hdl);
-       } else {
-               priv->cfmt = &ov772x_cfmts[0];
-               priv->win = &ov772x_win_sizes[0];
-       }
-
-       return ret;
-}
-
-static int ov772x_remove(struct i2c_client *client)
-{
-       struct ov772x_priv *priv = to_ov772x(i2c_get_clientdata(client));
-
-       v4l2_clk_put(priv->clk);
-       v4l2_device_unregister_subdev(&priv->subdev);
-       v4l2_ctrl_handler_free(&priv->hdl);
-       return 0;
-}
-
-static const struct i2c_device_id ov772x_id[] = {
-       { "ov772x", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, ov772x_id);
-
-static struct i2c_driver ov772x_i2c_driver = {
-       .driver = {
-               .name = "ov772x",
-       },
-       .probe    = ov772x_probe,
-       .remove   = ov772x_remove,
-       .id_table = ov772x_id,
-};
-
-module_i2c_driver(ov772x_i2c_driver);
-
-MODULE_DESCRIPTION("SoC Camera driver for ov772x");
-MODULE_AUTHOR("Kuninori Morimoto");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/soc_camera/ov9640.c b/drivers/media/i2c/soc_camera/ov9640.c
deleted file mode 100644 (file)
index eb91b82..0000000
+++ /dev/null
@@ -1,738 +0,0 @@
-/*
- * OmniVision OV96xx Camera Driver
- *
- * Copyright (C) 2009 Marek Vasut <marek.vasut@gmail.com>
- *
- * Based on ov772x camera driver:
- *
- * Copyright (C) 2008 Renesas Solutions Corp.
- * Kuninori Morimoto <morimoto.kuninori@renesas.com>
- *
- * Based on ov7670 and soc_camera_platform driver,
- *
- * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
- * Copyright (C) 2008 Magnus Damm
- * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
- *
- * 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.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/v4l2-mediabus.h>
-#include <linux/videodev2.h>
-
-#include <media/soc_camera.h>
-#include <media/v4l2-clk.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ctrls.h>
-
-#include "ov9640.h"
-
-#define to_ov9640_sensor(sd)   container_of(sd, struct ov9640_priv, subdev)
-
-/* default register setup */
-static const struct ov9640_reg ov9640_regs_dflt[] = {
-       { OV9640_COM5,  OV9640_COM5_SYSCLK | OV9640_COM5_LONGEXP },
-       { OV9640_COM6,  OV9640_COM6_OPT_BLC | OV9640_COM6_ADBLC_BIAS |
-                       OV9640_COM6_FMT_RST | OV9640_COM6_ADBLC_OPTEN },
-       { OV9640_PSHFT, OV9640_PSHFT_VAL(0x01) },
-       { OV9640_ACOM,  OV9640_ACOM_2X_ANALOG | OV9640_ACOM_RSVD },
-       { OV9640_TSLB,  OV9640_TSLB_YUYV_UYVY },
-       { OV9640_COM16, OV9640_COM16_RB_AVG },
-
-       /* Gamma curve P */
-       { 0x6c, 0x40 }, { 0x6d, 0x30 }, { 0x6e, 0x4b }, { 0x6f, 0x60 },
-       { 0x70, 0x70 }, { 0x71, 0x70 }, { 0x72, 0x70 }, { 0x73, 0x70 },
-       { 0x74, 0x60 }, { 0x75, 0x60 }, { 0x76, 0x50 }, { 0x77, 0x48 },
-       { 0x78, 0x3a }, { 0x79, 0x2e }, { 0x7a, 0x28 }, { 0x7b, 0x22 },
-
-       /* Gamma curve T */
-       { 0x7c, 0x04 }, { 0x7d, 0x07 }, { 0x7e, 0x10 }, { 0x7f, 0x28 },
-       { 0x80, 0x36 }, { 0x81, 0x44 }, { 0x82, 0x52 }, { 0x83, 0x60 },
-       { 0x84, 0x6c }, { 0x85, 0x78 }, { 0x86, 0x8c }, { 0x87, 0x9e },
-       { 0x88, 0xbb }, { 0x89, 0xd2 }, { 0x8a, 0xe6 },
-};
-
-/* Configurations
- * NOTE: for YUV, alter the following registers:
- *             COM12 |= OV9640_COM12_YUV_AVG
- *
- *      for RGB, alter the following registers:
- *             COM7  |= OV9640_COM7_RGB
- *             COM13 |= OV9640_COM13_RGB_AVG
- *             COM15 |= proper RGB color encoding mode
- */
-static const struct ov9640_reg ov9640_regs_qqcif[] = {
-       { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x0f) },
-       { OV9640_COM1,  OV9640_COM1_QQFMT | OV9640_COM1_HREF_2SKIP },
-       { OV9640_COM4,  OV9640_COM4_QQ_VP | OV9640_COM4_RSVD },
-       { OV9640_COM7,  OV9640_COM7_QCIF },
-       { OV9640_COM12, OV9640_COM12_RSVD },
-       { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
-       { OV9640_COM15, OV9640_COM15_OR_10F0 },
-};
-
-static const struct ov9640_reg ov9640_regs_qqvga[] = {
-       { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x07) },
-       { OV9640_COM1,  OV9640_COM1_QQFMT | OV9640_COM1_HREF_2SKIP },
-       { OV9640_COM4,  OV9640_COM4_QQ_VP | OV9640_COM4_RSVD },
-       { OV9640_COM7,  OV9640_COM7_QVGA },
-       { OV9640_COM12, OV9640_COM12_RSVD },
-       { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
-       { OV9640_COM15, OV9640_COM15_OR_10F0 },
-};
-
-static const struct ov9640_reg ov9640_regs_qcif[] = {
-       { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x07) },
-       { OV9640_COM4,  OV9640_COM4_QQ_VP | OV9640_COM4_RSVD },
-       { OV9640_COM7,  OV9640_COM7_QCIF },
-       { OV9640_COM12, OV9640_COM12_RSVD },
-       { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
-       { OV9640_COM15, OV9640_COM15_OR_10F0 },
-};
-
-static const struct ov9640_reg ov9640_regs_qvga[] = {
-       { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x03) },
-       { OV9640_COM4,  OV9640_COM4_QQ_VP | OV9640_COM4_RSVD },
-       { OV9640_COM7,  OV9640_COM7_QVGA },
-       { OV9640_COM12, OV9640_COM12_RSVD },
-       { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
-       { OV9640_COM15, OV9640_COM15_OR_10F0 },
-};
-
-static const struct ov9640_reg ov9640_regs_cif[] = {
-       { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x03) },
-       { OV9640_COM3,  OV9640_COM3_VP },
-       { OV9640_COM7,  OV9640_COM7_CIF },
-       { OV9640_COM12, OV9640_COM12_RSVD },
-       { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
-       { OV9640_COM15, OV9640_COM15_OR_10F0 },
-};
-
-static const struct ov9640_reg ov9640_regs_vga[] = {
-       { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x01) },
-       { OV9640_COM3,  OV9640_COM3_VP },
-       { OV9640_COM7,  OV9640_COM7_VGA },
-       { OV9640_COM12, OV9640_COM12_RSVD },
-       { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
-       { OV9640_COM15, OV9640_COM15_OR_10F0 },
-};
-
-static const struct ov9640_reg ov9640_regs_sxga[] = {
-       { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x01) },
-       { OV9640_COM3,  OV9640_COM3_VP },
-       { OV9640_COM7,  0 },
-       { OV9640_COM12, OV9640_COM12_RSVD },
-       { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
-       { OV9640_COM15, OV9640_COM15_OR_10F0 },
-};
-
-static const struct ov9640_reg ov9640_regs_yuv[] = {
-       { OV9640_MTX1,  0x58 },
-       { OV9640_MTX2,  0x48 },
-       { OV9640_MTX3,  0x10 },
-       { OV9640_MTX4,  0x28 },
-       { OV9640_MTX5,  0x48 },
-       { OV9640_MTX6,  0x70 },
-       { OV9640_MTX7,  0x40 },
-       { OV9640_MTX8,  0x40 },
-       { OV9640_MTX9,  0x40 },
-       { OV9640_MTXS,  0x0f },
-};
-
-static const struct ov9640_reg ov9640_regs_rgb[] = {
-       { OV9640_MTX1,  0x71 },
-       { OV9640_MTX2,  0x3e },
-       { OV9640_MTX3,  0x0c },
-       { OV9640_MTX4,  0x33 },
-       { OV9640_MTX5,  0x72 },
-       { OV9640_MTX6,  0x00 },
-       { OV9640_MTX7,  0x2b },
-       { OV9640_MTX8,  0x66 },
-       { OV9640_MTX9,  0xd2 },
-       { OV9640_MTXS,  0x65 },
-};
-
-static u32 ov9640_codes[] = {
-       MEDIA_BUS_FMT_UYVY8_2X8,
-       MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE,
-       MEDIA_BUS_FMT_RGB565_2X8_LE,
-};
-
-/* read a register */
-static int ov9640_reg_read(struct i2c_client *client, u8 reg, u8 *val)
-{
-       int ret;
-       u8 data = reg;
-       struct i2c_msg msg = {
-               .addr   = client->addr,
-               .flags  = 0,
-               .len    = 1,
-               .buf    = &data,
-       };
-
-       ret = i2c_transfer(client->adapter, &msg, 1);
-       if (ret < 0)
-               goto err;
-
-       msg.flags = I2C_M_RD;
-       ret = i2c_transfer(client->adapter, &msg, 1);
-       if (ret < 0)
-               goto err;
-
-       *val = data;
-       return 0;
-
-err:
-       dev_err(&client->dev, "Failed reading register 0x%02x!\n", reg);
-       return ret;
-}
-
-/* write a register */
-static int ov9640_reg_write(struct i2c_client *client, u8 reg, u8 val)
-{
-       int ret;
-       u8 _val;
-       unsigned char data[2] = { reg, val };
-       struct i2c_msg msg = {
-               .addr   = client->addr,
-               .flags  = 0,
-               .len    = 2,
-               .buf    = data,
-       };
-
-       ret = i2c_transfer(client->adapter, &msg, 1);
-       if (ret < 0) {
-               dev_err(&client->dev, "Failed writing register 0x%02x!\n", reg);
-               return ret;
-       }
-
-       /* we have to read the register back ... no idea why, maybe HW bug */
-       ret = ov9640_reg_read(client, reg, &_val);
-       if (ret)
-               dev_err(&client->dev,
-                       "Failed reading back register 0x%02x!\n", reg);
-
-       return 0;
-}
-
-
-/* Read a register, alter its bits, write it back */
-static int ov9640_reg_rmw(struct i2c_client *client, u8 reg, u8 set, u8 unset)
-{
-       u8 val;
-       int ret;
-
-       ret = ov9640_reg_read(client, reg, &val);
-       if (ret) {
-               dev_err(&client->dev,
-                       "[Read]-Modify-Write of register %02x failed!\n", reg);
-               return ret;
-       }
-
-       val |= set;
-       val &= ~unset;
-
-       ret = ov9640_reg_write(client, reg, val);
-       if (ret)
-               dev_err(&client->dev,
-                       "Read-Modify-[Write] of register %02x failed!\n", reg);
-
-       return ret;
-}
-
-/* Soft reset the camera. This has nothing to do with the RESET pin! */
-static int ov9640_reset(struct i2c_client *client)
-{
-       int ret;
-
-       ret = ov9640_reg_write(client, OV9640_COM7, OV9640_COM7_SCCB_RESET);
-       if (ret)
-               dev_err(&client->dev,
-                       "An error occurred while entering soft reset!\n");
-
-       return ret;
-}
-
-/* Start/Stop streaming from the device */
-static int ov9640_s_stream(struct v4l2_subdev *sd, int enable)
-{
-       return 0;
-}
-
-/* Set status of additional camera capabilities */
-static int ov9640_s_ctrl(struct v4l2_ctrl *ctrl)
-{
-       struct ov9640_priv *priv = container_of(ctrl->handler, struct ov9640_priv, hdl);
-       struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev);
-
-       switch (ctrl->id) {
-       case V4L2_CID_VFLIP:
-               if (ctrl->val)
-                       return ov9640_reg_rmw(client, OV9640_MVFP,
-                                                       OV9640_MVFP_V, 0);
-               return ov9640_reg_rmw(client, OV9640_MVFP, 0, OV9640_MVFP_V);
-       case V4L2_CID_HFLIP:
-               if (ctrl->val)
-                       return ov9640_reg_rmw(client, OV9640_MVFP,
-                                                       OV9640_MVFP_H, 0);
-               return ov9640_reg_rmw(client, OV9640_MVFP, 0, OV9640_MVFP_H);
-       }
-       return -EINVAL;
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int ov9640_get_register(struct v4l2_subdev *sd,
-                               struct v4l2_dbg_register *reg)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret;
-       u8 val;
-
-       if (reg->reg & ~0xff)
-               return -EINVAL;
-
-       reg->size = 1;
-
-       ret = ov9640_reg_read(client, reg->reg, &val);
-       if (ret)
-               return ret;
-
-       reg->val = (__u64)val;
-
-       return 0;
-}
-
-static int ov9640_set_register(struct v4l2_subdev *sd,
-                               const struct v4l2_dbg_register *reg)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (reg->reg & ~0xff || reg->val & ~0xff)
-               return -EINVAL;
-
-       return ov9640_reg_write(client, reg->reg, reg->val);
-}
-#endif
-
-static int ov9640_s_power(struct v4l2_subdev *sd, int on)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
-       struct ov9640_priv *priv = to_ov9640_sensor(sd);
-
-       return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
-}
-
-/* select nearest higher resolution for capture */
-static void ov9640_res_roundup(u32 *width, u32 *height)
-{
-       int i;
-       enum { QQCIF, QQVGA, QCIF, QVGA, CIF, VGA, SXGA };
-       static const int res_x[] = { 88, 160, 176, 320, 352, 640, 1280 };
-       static const int res_y[] = { 72, 120, 144, 240, 288, 480, 960 };
-
-       for (i = 0; i < ARRAY_SIZE(res_x); i++) {
-               if (res_x[i] >= *width && res_y[i] >= *height) {
-                       *width = res_x[i];
-                       *height = res_y[i];
-                       return;
-               }
-       }
-
-       *width = res_x[SXGA];
-       *height = res_y[SXGA];
-}
-
-/* Prepare necessary register changes depending on color encoding */
-static void ov9640_alter_regs(u32 code,
-                             struct ov9640_reg_alt *alt)
-{
-       switch (code) {
-       default:
-       case MEDIA_BUS_FMT_UYVY8_2X8:
-               alt->com12      = OV9640_COM12_YUV_AVG;
-               alt->com13      = OV9640_COM13_Y_DELAY_EN |
-                                       OV9640_COM13_YUV_DLY(0x01);
-               break;
-       case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE:
-               alt->com7       = OV9640_COM7_RGB;
-               alt->com13      = OV9640_COM13_RGB_AVG;
-               alt->com15      = OV9640_COM15_RGB_555;
-               break;
-       case MEDIA_BUS_FMT_RGB565_2X8_LE:
-               alt->com7       = OV9640_COM7_RGB;
-               alt->com13      = OV9640_COM13_RGB_AVG;
-               alt->com15      = OV9640_COM15_RGB_565;
-               break;
-       }
-}
-
-/* Setup registers according to resolution and color encoding */
-static int ov9640_write_regs(struct i2c_client *client, u32 width,
-               u32 code, struct ov9640_reg_alt *alts)
-{
-       const struct ov9640_reg *ov9640_regs, *matrix_regs;
-       int                     ov9640_regs_len, matrix_regs_len;
-       int                     i, ret;
-       u8                      val;
-
-       /* select register configuration for given resolution */
-       switch (width) {
-       case W_QQCIF:
-               ov9640_regs     = ov9640_regs_qqcif;
-               ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qqcif);
-               break;
-       case W_QQVGA:
-               ov9640_regs     = ov9640_regs_qqvga;
-               ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qqvga);
-               break;
-       case W_QCIF:
-               ov9640_regs     = ov9640_regs_qcif;
-               ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qcif);
-               break;
-       case W_QVGA:
-               ov9640_regs     = ov9640_regs_qvga;
-               ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qvga);
-               break;
-       case W_CIF:
-               ov9640_regs     = ov9640_regs_cif;
-               ov9640_regs_len = ARRAY_SIZE(ov9640_regs_cif);
-               break;
-       case W_VGA:
-               ov9640_regs     = ov9640_regs_vga;
-               ov9640_regs_len = ARRAY_SIZE(ov9640_regs_vga);
-               break;
-       case W_SXGA:
-               ov9640_regs     = ov9640_regs_sxga;
-               ov9640_regs_len = ARRAY_SIZE(ov9640_regs_sxga);
-               break;
-       default:
-               dev_err(&client->dev, "Failed to select resolution!\n");
-               return -EINVAL;
-       }
-
-       /* select color matrix configuration for given color encoding */
-       if (code == MEDIA_BUS_FMT_UYVY8_2X8) {
-               matrix_regs     = ov9640_regs_yuv;
-               matrix_regs_len = ARRAY_SIZE(ov9640_regs_yuv);
-       } else {
-               matrix_regs     = ov9640_regs_rgb;
-               matrix_regs_len = ARRAY_SIZE(ov9640_regs_rgb);
-       }
-
-       /* write register settings into the module */
-       for (i = 0; i < ov9640_regs_len; i++) {
-               val = ov9640_regs[i].val;
-
-               switch (ov9640_regs[i].reg) {
-               case OV9640_COM7:
-                       val |= alts->com7;
-                       break;
-               case OV9640_COM12:
-                       val |= alts->com12;
-                       break;
-               case OV9640_COM13:
-                       val |= alts->com13;
-                       break;
-               case OV9640_COM15:
-                       val |= alts->com15;
-                       break;
-               }
-
-               ret = ov9640_reg_write(client, ov9640_regs[i].reg, val);
-               if (ret)
-                       return ret;
-       }
-
-       /* write color matrix configuration into the module */
-       for (i = 0; i < matrix_regs_len; i++) {
-               ret = ov9640_reg_write(client, matrix_regs[i].reg,
-                                               matrix_regs[i].val);
-               if (ret)
-                       return ret;
-       }
-
-       return 0;
-}
-
-/* program default register values */
-static int ov9640_prog_dflt(struct i2c_client *client)
-{
-       int i, ret;
-
-       for (i = 0; i < ARRAY_SIZE(ov9640_regs_dflt); i++) {
-               ret = ov9640_reg_write(client, ov9640_regs_dflt[i].reg,
-                                               ov9640_regs_dflt[i].val);
-               if (ret)
-                       return ret;
-       }
-
-       /* wait for the changes to actually happen, 140ms are not enough yet */
-       mdelay(150);
-
-       return 0;
-}
-
-/* set the format we will capture in */
-static int ov9640_s_fmt(struct v4l2_subdev *sd,
-                       struct v4l2_mbus_framefmt *mf)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct ov9640_reg_alt alts = {0};
-       int ret;
-
-       ov9640_alter_regs(mf->code, &alts);
-
-       ov9640_reset(client);
-
-       ret = ov9640_prog_dflt(client);
-       if (ret)
-               return ret;
-
-       return ov9640_write_regs(client, mf->width, mf->code, &alts);
-}
-
-static int ov9640_set_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_format *format)
-{
-       struct v4l2_mbus_framefmt *mf = &format->format;
-
-       if (format->pad)
-               return -EINVAL;
-
-       ov9640_res_roundup(&mf->width, &mf->height);
-
-       mf->field = V4L2_FIELD_NONE;
-
-       switch (mf->code) {
-       case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE:
-       case MEDIA_BUS_FMT_RGB565_2X8_LE:
-               mf->colorspace = V4L2_COLORSPACE_SRGB;
-               break;
-       default:
-               mf->code = MEDIA_BUS_FMT_UYVY8_2X8;
-               /* fall through */
-       case MEDIA_BUS_FMT_UYVY8_2X8:
-               mf->colorspace = V4L2_COLORSPACE_JPEG;
-               break;
-       }
-
-       if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
-               return ov9640_s_fmt(sd, mf);
-
-       cfg->try_fmt = *mf;
-       return 0;
-}
-
-static int ov9640_enum_mbus_code(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_mbus_code_enum *code)
-{
-       if (code->pad || code->index >= ARRAY_SIZE(ov9640_codes))
-               return -EINVAL;
-
-       code->code = ov9640_codes[code->index];
-       return 0;
-}
-
-static int ov9640_get_selection(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_selection *sel)
-{
-       if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
-               return -EINVAL;
-
-       sel->r.left = 0;
-       sel->r.top = 0;
-       switch (sel->target) {
-       case V4L2_SEL_TGT_CROP_BOUNDS:
-       case V4L2_SEL_TGT_CROP:
-               sel->r.width = W_SXGA;
-               sel->r.height = H_SXGA;
-               return 0;
-       default:
-               return -EINVAL;
-       }
-}
-
-static int ov9640_video_probe(struct i2c_client *client)
-{
-       struct v4l2_subdev *sd = i2c_get_clientdata(client);
-       struct ov9640_priv *priv = to_ov9640_sensor(sd);
-       u8              pid, ver, midh, midl;
-       const char      *devname;
-       int             ret;
-
-       ret = ov9640_s_power(&priv->subdev, 1);
-       if (ret < 0)
-               return ret;
-
-       /*
-        * check and show product ID and manufacturer ID
-        */
-
-       ret = ov9640_reg_read(client, OV9640_PID, &pid);
-       if (!ret)
-               ret = ov9640_reg_read(client, OV9640_VER, &ver);
-       if (!ret)
-               ret = ov9640_reg_read(client, OV9640_MIDH, &midh);
-       if (!ret)
-               ret = ov9640_reg_read(client, OV9640_MIDL, &midl);
-       if (ret)
-               goto done;
-
-       switch (VERSION(pid, ver)) {
-       case OV9640_V2:
-               devname         = "ov9640";
-               priv->revision  = 2;
-               break;
-       case OV9640_V3:
-               devname         = "ov9640";
-               priv->revision  = 3;
-               break;
-       default:
-               dev_err(&client->dev, "Product ID error %x:%x\n", pid, ver);
-               ret = -ENODEV;
-               goto done;
-       }
-
-       dev_info(&client->dev, "%s Product ID %0x:%0x Manufacturer ID %x:%x\n",
-                devname, pid, ver, midh, midl);
-
-       ret = v4l2_ctrl_handler_setup(&priv->hdl);
-
-done:
-       ov9640_s_power(&priv->subdev, 0);
-       return ret;
-}
-
-static const struct v4l2_ctrl_ops ov9640_ctrl_ops = {
-       .s_ctrl = ov9640_s_ctrl,
-};
-
-static const struct v4l2_subdev_core_ops ov9640_core_ops = {
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       .g_register             = ov9640_get_register,
-       .s_register             = ov9640_set_register,
-#endif
-       .s_power                = ov9640_s_power,
-};
-
-/* Request bus settings on camera side */
-static int ov9640_g_mbus_config(struct v4l2_subdev *sd,
-                               struct v4l2_mbus_config *cfg)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
-
-       cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
-               V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
-               V4L2_MBUS_DATA_ACTIVE_HIGH;
-       cfg->type = V4L2_MBUS_PARALLEL;
-       cfg->flags = soc_camera_apply_board_flags(ssdd, cfg);
-
-       return 0;
-}
-
-static const struct v4l2_subdev_video_ops ov9640_video_ops = {
-       .s_stream       = ov9640_s_stream,
-       .g_mbus_config  = ov9640_g_mbus_config,
-};
-
-static const struct v4l2_subdev_pad_ops ov9640_pad_ops = {
-       .enum_mbus_code = ov9640_enum_mbus_code,
-       .get_selection  = ov9640_get_selection,
-       .set_fmt        = ov9640_set_fmt,
-};
-
-static const struct v4l2_subdev_ops ov9640_subdev_ops = {
-       .core   = &ov9640_core_ops,
-       .video  = &ov9640_video_ops,
-       .pad    = &ov9640_pad_ops,
-};
-
-/*
- * i2c_driver function
- */
-static int ov9640_probe(struct i2c_client *client,
-                       const struct i2c_device_id *did)
-{
-       struct ov9640_priv *priv;
-       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
-       int ret;
-
-       if (!ssdd) {
-               dev_err(&client->dev, "Missing platform_data for driver\n");
-               return -EINVAL;
-       }
-
-       priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-
-       v4l2_i2c_subdev_init(&priv->subdev, client, &ov9640_subdev_ops);
-
-       v4l2_ctrl_handler_init(&priv->hdl, 2);
-       v4l2_ctrl_new_std(&priv->hdl, &ov9640_ctrl_ops,
-                       V4L2_CID_VFLIP, 0, 1, 1, 0);
-       v4l2_ctrl_new_std(&priv->hdl, &ov9640_ctrl_ops,
-                       V4L2_CID_HFLIP, 0, 1, 1, 0);
-       priv->subdev.ctrl_handler = &priv->hdl;
-       if (priv->hdl.error)
-               return priv->hdl.error;
-
-       priv->clk = v4l2_clk_get(&client->dev, "mclk");
-       if (IS_ERR(priv->clk)) {
-               ret = PTR_ERR(priv->clk);
-               goto eclkget;
-       }
-
-       ret = ov9640_video_probe(client);
-       if (ret) {
-               v4l2_clk_put(priv->clk);
-eclkget:
-               v4l2_ctrl_handler_free(&priv->hdl);
-       }
-
-       return ret;
-}
-
-static int ov9640_remove(struct i2c_client *client)
-{
-       struct v4l2_subdev *sd = i2c_get_clientdata(client);
-       struct ov9640_priv *priv = to_ov9640_sensor(sd);
-
-       v4l2_clk_put(priv->clk);
-       v4l2_device_unregister_subdev(&priv->subdev);
-       v4l2_ctrl_handler_free(&priv->hdl);
-       return 0;
-}
-
-static const struct i2c_device_id ov9640_id[] = {
-       { "ov9640", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, ov9640_id);
-
-static struct i2c_driver ov9640_i2c_driver = {
-       .driver = {
-               .name = "ov9640",
-       },
-       .probe    = ov9640_probe,
-       .remove   = ov9640_remove,
-       .id_table = ov9640_id,
-};
-
-module_i2c_driver(ov9640_i2c_driver);
-
-MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV96xx");
-MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/soc_camera/ov9740.c b/drivers/media/i2c/soc_camera/ov9740.c
deleted file mode 100644 (file)
index a07d314..0000000
+++ /dev/null
@@ -1,996 +0,0 @@
-/*
- * OmniVision OV9740 Camera Driver
- *
- * Copyright (C) 2011 NVIDIA Corporation
- *
- * Based on ov9640 camera driver.
- *
- * 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.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/v4l2-mediabus.h>
-
-#include <media/soc_camera.h>
-#include <media/v4l2-clk.h>
-#include <media/v4l2-ctrls.h>
-
-#define to_ov9740(sd)          container_of(sd, struct ov9740_priv, subdev)
-
-/* General Status Registers */
-#define OV9740_MODEL_ID_HI             0x0000
-#define OV9740_MODEL_ID_LO             0x0001
-#define OV9740_REVISION_NUMBER         0x0002
-#define OV9740_MANUFACTURER_ID         0x0003
-#define OV9740_SMIA_VERSION            0x0004
-
-/* General Setup Registers */
-#define OV9740_MODE_SELECT             0x0100
-#define OV9740_IMAGE_ORT               0x0101
-#define OV9740_SOFTWARE_RESET          0x0103
-#define OV9740_GRP_PARAM_HOLD          0x0104
-#define OV9740_MSK_CORRUP_FM           0x0105
-
-/* Timing Setting */
-#define OV9740_FRM_LENGTH_LN_HI                0x0340 /* VTS */
-#define OV9740_FRM_LENGTH_LN_LO                0x0341 /* VTS */
-#define OV9740_LN_LENGTH_PCK_HI                0x0342 /* HTS */
-#define OV9740_LN_LENGTH_PCK_LO                0x0343 /* HTS */
-#define OV9740_X_ADDR_START_HI         0x0344
-#define OV9740_X_ADDR_START_LO         0x0345
-#define OV9740_Y_ADDR_START_HI         0x0346
-#define OV9740_Y_ADDR_START_LO         0x0347
-#define OV9740_X_ADDR_END_HI           0x0348
-#define OV9740_X_ADDR_END_LO           0x0349
-#define OV9740_Y_ADDR_END_HI           0x034a
-#define OV9740_Y_ADDR_END_LO           0x034b
-#define OV9740_X_OUTPUT_SIZE_HI                0x034c
-#define OV9740_X_OUTPUT_SIZE_LO                0x034d
-#define OV9740_Y_OUTPUT_SIZE_HI                0x034e
-#define OV9740_Y_OUTPUT_SIZE_LO                0x034f
-
-/* IO Control Registers */
-#define OV9740_IO_CREL00               0x3002
-#define OV9740_IO_CREL01               0x3004
-#define OV9740_IO_CREL02               0x3005
-#define OV9740_IO_OUTPUT_SEL01         0x3026
-#define OV9740_IO_OUTPUT_SEL02         0x3027
-
-/* AWB Registers */
-#define OV9740_AWB_MANUAL_CTRL         0x3406
-
-/* Analog Control Registers */
-#define OV9740_ANALOG_CTRL01           0x3601
-#define OV9740_ANALOG_CTRL02           0x3602
-#define OV9740_ANALOG_CTRL03           0x3603
-#define OV9740_ANALOG_CTRL04           0x3604
-#define OV9740_ANALOG_CTRL10           0x3610
-#define OV9740_ANALOG_CTRL12           0x3612
-#define OV9740_ANALOG_CTRL15           0x3615
-#define OV9740_ANALOG_CTRL20           0x3620
-#define OV9740_ANALOG_CTRL21           0x3621
-#define OV9740_ANALOG_CTRL22           0x3622
-#define OV9740_ANALOG_CTRL30           0x3630
-#define OV9740_ANALOG_CTRL31           0x3631
-#define OV9740_ANALOG_CTRL32           0x3632
-#define OV9740_ANALOG_CTRL33           0x3633
-
-/* Sensor Control */
-#define OV9740_SENSOR_CTRL03           0x3703
-#define OV9740_SENSOR_CTRL04           0x3704
-#define OV9740_SENSOR_CTRL05           0x3705
-#define OV9740_SENSOR_CTRL07           0x3707
-
-/* Timing Control */
-#define OV9740_TIMING_CTRL17           0x3817
-#define OV9740_TIMING_CTRL19           0x3819
-#define OV9740_TIMING_CTRL33           0x3833
-#define OV9740_TIMING_CTRL35           0x3835
-
-/* Banding Filter */
-#define OV9740_AEC_MAXEXPO_60_H                0x3a02
-#define OV9740_AEC_MAXEXPO_60_L                0x3a03
-#define OV9740_AEC_B50_STEP_HI         0x3a08
-#define OV9740_AEC_B50_STEP_LO         0x3a09
-#define OV9740_AEC_B60_STEP_HI         0x3a0a
-#define OV9740_AEC_B60_STEP_LO         0x3a0b
-#define OV9740_AEC_CTRL0D              0x3a0d
-#define OV9740_AEC_CTRL0E              0x3a0e
-#define OV9740_AEC_MAXEXPO_50_H                0x3a14
-#define OV9740_AEC_MAXEXPO_50_L                0x3a15
-
-/* AEC/AGC Control */
-#define OV9740_AEC_ENABLE              0x3503
-#define OV9740_GAIN_CEILING_01         0x3a18
-#define OV9740_GAIN_CEILING_02         0x3a19
-#define OV9740_AEC_HI_THRESHOLD                0x3a11
-#define OV9740_AEC_3A1A                        0x3a1a
-#define OV9740_AEC_CTRL1B_WPT2         0x3a1b
-#define OV9740_AEC_CTRL0F_WPT          0x3a0f
-#define OV9740_AEC_CTRL10_BPT          0x3a10
-#define OV9740_AEC_CTRL1E_BPT2         0x3a1e
-#define OV9740_AEC_LO_THRESHOLD                0x3a1f
-
-/* BLC Control */
-#define OV9740_BLC_AUTO_ENABLE         0x4002
-#define OV9740_BLC_MODE                        0x4005
-
-/* VFIFO */
-#define OV9740_VFIFO_READ_START_HI     0x4608
-#define OV9740_VFIFO_READ_START_LO     0x4609
-
-/* DVP Control */
-#define OV9740_DVP_VSYNC_CTRL02                0x4702
-#define OV9740_DVP_VSYNC_MODE          0x4704
-#define OV9740_DVP_VSYNC_CTRL06                0x4706
-
-/* PLL Setting */
-#define OV9740_PLL_MODE_CTRL01         0x3104
-#define OV9740_PRE_PLL_CLK_DIV         0x0305
-#define OV9740_PLL_MULTIPLIER          0x0307
-#define OV9740_VT_SYS_CLK_DIV          0x0303
-#define OV9740_VT_PIX_CLK_DIV          0x0301
-#define OV9740_PLL_CTRL3010            0x3010
-#define OV9740_VFIFO_CTRL00            0x460e
-
-/* ISP Control */
-#define OV9740_ISP_CTRL00              0x5000
-#define OV9740_ISP_CTRL01              0x5001
-#define OV9740_ISP_CTRL03              0x5003
-#define OV9740_ISP_CTRL05              0x5005
-#define OV9740_ISP_CTRL12              0x5012
-#define OV9740_ISP_CTRL19              0x5019
-#define OV9740_ISP_CTRL1A              0x501a
-#define OV9740_ISP_CTRL1E              0x501e
-#define OV9740_ISP_CTRL1F              0x501f
-#define OV9740_ISP_CTRL20              0x5020
-#define OV9740_ISP_CTRL21              0x5021
-
-/* AWB */
-#define OV9740_AWB_CTRL00              0x5180
-#define OV9740_AWB_CTRL01              0x5181
-#define OV9740_AWB_CTRL02              0x5182
-#define OV9740_AWB_CTRL03              0x5183
-#define OV9740_AWB_ADV_CTRL01          0x5184
-#define OV9740_AWB_ADV_CTRL02          0x5185
-#define OV9740_AWB_ADV_CTRL03          0x5186
-#define OV9740_AWB_ADV_CTRL04          0x5187
-#define OV9740_AWB_ADV_CTRL05          0x5188
-#define OV9740_AWB_ADV_CTRL06          0x5189
-#define OV9740_AWB_ADV_CTRL07          0x518a
-#define OV9740_AWB_ADV_CTRL08          0x518b
-#define OV9740_AWB_ADV_CTRL09          0x518c
-#define OV9740_AWB_ADV_CTRL10          0x518d
-#define OV9740_AWB_ADV_CTRL11          0x518e
-#define OV9740_AWB_CTRL0F              0x518f
-#define OV9740_AWB_CTRL10              0x5190
-#define OV9740_AWB_CTRL11              0x5191
-#define OV9740_AWB_CTRL12              0x5192
-#define OV9740_AWB_CTRL13              0x5193
-#define OV9740_AWB_CTRL14              0x5194
-
-/* MIPI Control */
-#define OV9740_MIPI_CTRL00             0x4800
-#define OV9740_MIPI_3837               0x3837
-#define OV9740_MIPI_CTRL01             0x4801
-#define OV9740_MIPI_CTRL03             0x4803
-#define OV9740_MIPI_CTRL05             0x4805
-#define OV9740_VFIFO_RD_CTRL           0x4601
-#define OV9740_MIPI_CTRL_3012          0x3012
-#define OV9740_SC_CMMM_MIPI_CTR                0x3014
-
-#define OV9740_MAX_WIDTH               1280
-#define OV9740_MAX_HEIGHT              720
-
-/* Misc. structures */
-struct ov9740_reg {
-       u16                             reg;
-       u8                              val;
-};
-
-struct ov9740_priv {
-       struct v4l2_subdev              subdev;
-       struct v4l2_ctrl_handler        hdl;
-       struct v4l2_clk                 *clk;
-
-       u16                             model;
-       u8                              revision;
-       u8                              manid;
-       u8                              smiaver;
-
-       bool                            flag_vflip;
-       bool                            flag_hflip;
-
-       /* For suspend/resume. */
-       struct v4l2_mbus_framefmt       current_mf;
-       bool                            current_enable;
-};
-
-static const struct ov9740_reg ov9740_defaults[] = {
-       /* Software Reset */
-       { OV9740_SOFTWARE_RESET,        0x01 },
-
-       /* Banding Filter */
-       { OV9740_AEC_B50_STEP_HI,       0x00 },
-       { OV9740_AEC_B50_STEP_LO,       0xe8 },
-       { OV9740_AEC_CTRL0E,            0x03 },
-       { OV9740_AEC_MAXEXPO_50_H,      0x15 },
-       { OV9740_AEC_MAXEXPO_50_L,      0xc6 },
-       { OV9740_AEC_B60_STEP_HI,       0x00 },
-       { OV9740_AEC_B60_STEP_LO,       0xc0 },
-       { OV9740_AEC_CTRL0D,            0x04 },
-       { OV9740_AEC_MAXEXPO_60_H,      0x18 },
-       { OV9740_AEC_MAXEXPO_60_L,      0x20 },
-
-       /* LC */
-       { 0x5842, 0x02 }, { 0x5843, 0x5e }, { 0x5844, 0x04 }, { 0x5845, 0x32 },
-       { 0x5846, 0x03 }, { 0x5847, 0x29 }, { 0x5848, 0x02 }, { 0x5849, 0xcc },
-
-       /* Un-documented OV9740 registers */
-       { 0x5800, 0x29 }, { 0x5801, 0x25 }, { 0x5802, 0x20 }, { 0x5803, 0x21 },
-       { 0x5804, 0x26 }, { 0x5805, 0x2e }, { 0x5806, 0x11 }, { 0x5807, 0x0c },
-       { 0x5808, 0x09 }, { 0x5809, 0x0a }, { 0x580a, 0x0e }, { 0x580b, 0x16 },
-       { 0x580c, 0x06 }, { 0x580d, 0x02 }, { 0x580e, 0x00 }, { 0x580f, 0x00 },
-       { 0x5810, 0x04 }, { 0x5811, 0x0a }, { 0x5812, 0x05 }, { 0x5813, 0x02 },
-       { 0x5814, 0x00 }, { 0x5815, 0x00 }, { 0x5816, 0x03 }, { 0x5817, 0x09 },
-       { 0x5818, 0x0f }, { 0x5819, 0x0a }, { 0x581a, 0x07 }, { 0x581b, 0x08 },
-       { 0x581c, 0x0b }, { 0x581d, 0x14 }, { 0x581e, 0x28 }, { 0x581f, 0x23 },
-       { 0x5820, 0x1d }, { 0x5821, 0x1e }, { 0x5822, 0x24 }, { 0x5823, 0x2a },
-       { 0x5824, 0x4f }, { 0x5825, 0x6f }, { 0x5826, 0x5f }, { 0x5827, 0x7f },
-       { 0x5828, 0x9f }, { 0x5829, 0x5f }, { 0x582a, 0x8f }, { 0x582b, 0x9e },
-       { 0x582c, 0x8f }, { 0x582d, 0x9f }, { 0x582e, 0x4f }, { 0x582f, 0x87 },
-       { 0x5830, 0x86 }, { 0x5831, 0x97 }, { 0x5832, 0xae }, { 0x5833, 0x3f },
-       { 0x5834, 0x8e }, { 0x5835, 0x7c }, { 0x5836, 0x7e }, { 0x5837, 0xaf },
-       { 0x5838, 0x8f }, { 0x5839, 0x8f }, { 0x583a, 0x9f }, { 0x583b, 0x7f },
-       { 0x583c, 0x5f },
-
-       /* Y Gamma */
-       { 0x5480, 0x07 }, { 0x5481, 0x18 }, { 0x5482, 0x2c }, { 0x5483, 0x4e },
-       { 0x5484, 0x5e }, { 0x5485, 0x6b }, { 0x5486, 0x77 }, { 0x5487, 0x82 },
-       { 0x5488, 0x8c }, { 0x5489, 0x95 }, { 0x548a, 0xa4 }, { 0x548b, 0xb1 },
-       { 0x548c, 0xc6 }, { 0x548d, 0xd8 }, { 0x548e, 0xe9 },
-
-       /* UV Gamma */
-       { 0x5490, 0x0f }, { 0x5491, 0xff }, { 0x5492, 0x0d }, { 0x5493, 0x05 },
-       { 0x5494, 0x07 }, { 0x5495, 0x1a }, { 0x5496, 0x04 }, { 0x5497, 0x01 },
-       { 0x5498, 0x03 }, { 0x5499, 0x53 }, { 0x549a, 0x02 }, { 0x549b, 0xeb },
-       { 0x549c, 0x02 }, { 0x549d, 0xa0 }, { 0x549e, 0x02 }, { 0x549f, 0x67 },
-       { 0x54a0, 0x02 }, { 0x54a1, 0x3b }, { 0x54a2, 0x02 }, { 0x54a3, 0x18 },
-       { 0x54a4, 0x01 }, { 0x54a5, 0xe7 }, { 0x54a6, 0x01 }, { 0x54a7, 0xc3 },
-       { 0x54a8, 0x01 }, { 0x54a9, 0x94 }, { 0x54aa, 0x01 }, { 0x54ab, 0x72 },
-       { 0x54ac, 0x01 }, { 0x54ad, 0x57 },
-
-       /* AWB */
-       { OV9740_AWB_CTRL00,            0xf0 },
-       { OV9740_AWB_CTRL01,            0x00 },
-       { OV9740_AWB_CTRL02,            0x41 },
-       { OV9740_AWB_CTRL03,            0x42 },
-       { OV9740_AWB_ADV_CTRL01,        0x8a },
-       { OV9740_AWB_ADV_CTRL02,        0x61 },
-       { OV9740_AWB_ADV_CTRL03,        0xce },
-       { OV9740_AWB_ADV_CTRL04,        0xa8 },
-       { OV9740_AWB_ADV_CTRL05,        0x17 },
-       { OV9740_AWB_ADV_CTRL06,        0x1f },
-       { OV9740_AWB_ADV_CTRL07,        0x27 },
-       { OV9740_AWB_ADV_CTRL08,        0x41 },
-       { OV9740_AWB_ADV_CTRL09,        0x34 },
-       { OV9740_AWB_ADV_CTRL10,        0xf0 },
-       { OV9740_AWB_ADV_CTRL11,        0x10 },
-       { OV9740_AWB_CTRL0F,            0xff },
-       { OV9740_AWB_CTRL10,            0x00 },
-       { OV9740_AWB_CTRL11,            0xff },
-       { OV9740_AWB_CTRL12,            0x00 },
-       { OV9740_AWB_CTRL13,            0xff },
-       { OV9740_AWB_CTRL14,            0x00 },
-
-       /* CIP */
-       { 0x530d, 0x12 },
-
-       /* CMX */
-       { 0x5380, 0x01 }, { 0x5381, 0x00 }, { 0x5382, 0x00 }, { 0x5383, 0x17 },
-       { 0x5384, 0x00 }, { 0x5385, 0x01 }, { 0x5386, 0x00 }, { 0x5387, 0x00 },
-       { 0x5388, 0x00 }, { 0x5389, 0xe0 }, { 0x538a, 0x00 }, { 0x538b, 0x20 },
-       { 0x538c, 0x00 }, { 0x538d, 0x00 }, { 0x538e, 0x00 }, { 0x538f, 0x16 },
-       { 0x5390, 0x00 }, { 0x5391, 0x9c }, { 0x5392, 0x00 }, { 0x5393, 0xa0 },
-       { 0x5394, 0x18 },
-
-       /* 50/60 Detection */
-       { 0x3c0a, 0x9c }, { 0x3c0b, 0x3f },
-
-       /* Output Select */
-       { OV9740_IO_OUTPUT_SEL01,       0x00 },
-       { OV9740_IO_OUTPUT_SEL02,       0x00 },
-       { OV9740_IO_CREL00,             0x00 },
-       { OV9740_IO_CREL01,             0x00 },
-       { OV9740_IO_CREL02,             0x00 },
-
-       /* AWB Control */
-       { OV9740_AWB_MANUAL_CTRL,       0x00 },
-
-       /* Analog Control */
-       { OV9740_ANALOG_CTRL03,         0xaa },
-       { OV9740_ANALOG_CTRL32,         0x2f },
-       { OV9740_ANALOG_CTRL20,         0x66 },
-       { OV9740_ANALOG_CTRL21,         0xc0 },
-       { OV9740_ANALOG_CTRL31,         0x52 },
-       { OV9740_ANALOG_CTRL33,         0x50 },
-       { OV9740_ANALOG_CTRL30,         0xca },
-       { OV9740_ANALOG_CTRL04,         0x0c },
-       { OV9740_ANALOG_CTRL01,         0x40 },
-       { OV9740_ANALOG_CTRL02,         0x16 },
-       { OV9740_ANALOG_CTRL10,         0xa1 },
-       { OV9740_ANALOG_CTRL12,         0x24 },
-       { OV9740_ANALOG_CTRL22,         0x9f },
-       { OV9740_ANALOG_CTRL15,         0xf0 },
-
-       /* Sensor Control */
-       { OV9740_SENSOR_CTRL03,         0x42 },
-       { OV9740_SENSOR_CTRL04,         0x10 },
-       { OV9740_SENSOR_CTRL05,         0x45 },
-       { OV9740_SENSOR_CTRL07,         0x14 },
-
-       /* Timing Control */
-       { OV9740_TIMING_CTRL33,         0x04 },
-       { OV9740_TIMING_CTRL35,         0x02 },
-       { OV9740_TIMING_CTRL19,         0x6e },
-       { OV9740_TIMING_CTRL17,         0x94 },
-
-       /* AEC/AGC Control */
-       { OV9740_AEC_ENABLE,            0x10 },
-       { OV9740_GAIN_CEILING_01,       0x00 },
-       { OV9740_GAIN_CEILING_02,       0x7f },
-       { OV9740_AEC_HI_THRESHOLD,      0xa0 },
-       { OV9740_AEC_3A1A,              0x05 },
-       { OV9740_AEC_CTRL1B_WPT2,       0x50 },
-       { OV9740_AEC_CTRL0F_WPT,        0x50 },
-       { OV9740_AEC_CTRL10_BPT,        0x4c },
-       { OV9740_AEC_CTRL1E_BPT2,       0x4c },
-       { OV9740_AEC_LO_THRESHOLD,      0x26 },
-
-       /* BLC Control */
-       { OV9740_BLC_AUTO_ENABLE,       0x45 },
-       { OV9740_BLC_MODE,              0x18 },
-
-       /* DVP Control */
-       { OV9740_DVP_VSYNC_CTRL02,      0x04 },
-       { OV9740_DVP_VSYNC_MODE,        0x00 },
-       { OV9740_DVP_VSYNC_CTRL06,      0x08 },
-
-       /* PLL Setting */
-       { OV9740_PLL_MODE_CTRL01,       0x20 },
-       { OV9740_PRE_PLL_CLK_DIV,       0x03 },
-       { OV9740_PLL_MULTIPLIER,        0x4c },
-       { OV9740_VT_SYS_CLK_DIV,        0x01 },
-       { OV9740_VT_PIX_CLK_DIV,        0x08 },
-       { OV9740_PLL_CTRL3010,          0x01 },
-       { OV9740_VFIFO_CTRL00,          0x82 },
-
-       /* Timing Setting */
-       /* VTS */
-       { OV9740_FRM_LENGTH_LN_HI,      0x03 },
-       { OV9740_FRM_LENGTH_LN_LO,      0x07 },
-       /* HTS */
-       { OV9740_LN_LENGTH_PCK_HI,      0x06 },
-       { OV9740_LN_LENGTH_PCK_LO,      0x62 },
-
-       /* MIPI Control */
-       { OV9740_MIPI_CTRL00,           0x44 }, /* 0x64 for discontinuous clk */
-       { OV9740_MIPI_3837,             0x01 },
-       { OV9740_MIPI_CTRL01,           0x0f },
-       { OV9740_MIPI_CTRL03,           0x05 },
-       { OV9740_MIPI_CTRL05,           0x10 },
-       { OV9740_VFIFO_RD_CTRL,         0x16 },
-       { OV9740_MIPI_CTRL_3012,        0x70 },
-       { OV9740_SC_CMMM_MIPI_CTR,      0x01 },
-
-       /* YUYV order */
-       { OV9740_ISP_CTRL19,            0x02 },
-};
-
-static u32 ov9740_codes[] = {
-       MEDIA_BUS_FMT_YUYV8_2X8,
-};
-
-/* read a register */
-static int ov9740_reg_read(struct i2c_client *client, u16 reg, u8 *val)
-{
-       int ret;
-       struct i2c_msg msg[] = {
-               {
-                       .addr   = client->addr,
-                       .flags  = 0,
-                       .len    = 2,
-                       .buf    = (u8 *)&reg,
-               },
-               {
-                       .addr   = client->addr,
-                       .flags  = I2C_M_RD,
-                       .len    = 1,
-                       .buf    = val,
-               },
-       };
-
-       reg = swab16(reg);
-
-       ret = i2c_transfer(client->adapter, msg, 2);
-       if (ret < 0) {
-               dev_err(&client->dev, "Failed reading register 0x%04x!\n", reg);
-               return ret;
-       }
-
-       return 0;
-}
-
-/* write a register */
-static int ov9740_reg_write(struct i2c_client *client, u16 reg, u8 val)
-{
-       struct i2c_msg msg;
-       struct {
-               u16 reg;
-               u8 val;
-       } __packed buf;
-       int ret;
-
-       reg = swab16(reg);
-
-       buf.reg = reg;
-       buf.val = val;
-
-       msg.addr        = client->addr;
-       msg.flags       = 0;
-       msg.len         = 3;
-       msg.buf         = (u8 *)&buf;
-
-       ret = i2c_transfer(client->adapter, &msg, 1);
-       if (ret < 0) {
-               dev_err(&client->dev, "Failed writing register 0x%04x!\n", reg);
-               return ret;
-       }
-
-       return 0;
-}
-
-
-/* Read a register, alter its bits, write it back */
-static int ov9740_reg_rmw(struct i2c_client *client, u16 reg, u8 set, u8 unset)
-{
-       u8 val;
-       int ret;
-
-       ret = ov9740_reg_read(client, reg, &val);
-       if (ret < 0) {
-               dev_err(&client->dev,
-                       "[Read]-Modify-Write of register 0x%04x failed!\n",
-                       reg);
-               return ret;
-       }
-
-       val |= set;
-       val &= ~unset;
-
-       ret = ov9740_reg_write(client, reg, val);
-       if (ret < 0) {
-               dev_err(&client->dev,
-                       "Read-Modify-[Write] of register 0x%04x failed!\n",
-                       reg);
-               return ret;
-       }
-
-       return 0;
-}
-
-static int ov9740_reg_write_array(struct i2c_client *client,
-                                 const struct ov9740_reg *regarray,
-                                 int regarraylen)
-{
-       int i;
-       int ret;
-
-       for (i = 0; i < regarraylen; i++) {
-               ret = ov9740_reg_write(client,
-                                      regarray[i].reg, regarray[i].val);
-               if (ret < 0)
-                       return ret;
-       }
-
-       return 0;
-}
-
-/* Start/Stop streaming from the device */
-static int ov9740_s_stream(struct v4l2_subdev *sd, int enable)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct ov9740_priv *priv = to_ov9740(sd);
-       int ret;
-
-       /* Program orientation register. */
-       if (priv->flag_vflip)
-               ret = ov9740_reg_rmw(client, OV9740_IMAGE_ORT, 0x2, 0);
-       else
-               ret = ov9740_reg_rmw(client, OV9740_IMAGE_ORT, 0, 0x2);
-       if (ret < 0)
-               return ret;
-
-       if (priv->flag_hflip)
-               ret = ov9740_reg_rmw(client, OV9740_IMAGE_ORT, 0x1, 0);
-       else
-               ret = ov9740_reg_rmw(client, OV9740_IMAGE_ORT, 0, 0x1);
-       if (ret < 0)
-               return ret;
-
-       if (enable) {
-               dev_dbg(&client->dev, "Enabling Streaming\n");
-               /* Start Streaming */
-               ret = ov9740_reg_write(client, OV9740_MODE_SELECT, 0x01);
-
-       } else {
-               dev_dbg(&client->dev, "Disabling Streaming\n");
-               /* Software Reset */
-               ret = ov9740_reg_write(client, OV9740_SOFTWARE_RESET, 0x01);
-               if (!ret)
-                       /* Setting Streaming to Standby */
-                       ret = ov9740_reg_write(client, OV9740_MODE_SELECT,
-                                              0x00);
-       }
-
-       priv->current_enable = enable;
-
-       return ret;
-}
-
-/* select nearest higher resolution for capture */
-static void ov9740_res_roundup(u32 *width, u32 *height)
-{
-       /* Width must be a multiple of 4 pixels. */
-       *width = ALIGN(*width, 4);
-
-       /* Max resolution is 1280x720 (720p). */
-       if (*width > OV9740_MAX_WIDTH)
-               *width = OV9740_MAX_WIDTH;
-
-       if (*height > OV9740_MAX_HEIGHT)
-               *height = OV9740_MAX_HEIGHT;
-}
-
-/* Setup registers according to resolution and color encoding */
-static int ov9740_set_res(struct i2c_client *client, u32 width, u32 height)
-{
-       u32 x_start;
-       u32 y_start;
-       u32 x_end;
-       u32 y_end;
-       bool scaling = false;
-       u32 scale_input_x;
-       u32 scale_input_y;
-       int ret;
-
-       if ((width != OV9740_MAX_WIDTH) || (height != OV9740_MAX_HEIGHT))
-               scaling = true;
-
-       /*
-        * Try to use as much of the sensor area as possible when supporting
-        * smaller resolutions.  Depending on the aspect ratio of the
-        * chosen resolution, we can either use the full width of the sensor,
-        * or the full height of the sensor (or both if the aspect ratio is
-        * the same as 1280x720.
-        */
-       if ((OV9740_MAX_WIDTH * height) > (OV9740_MAX_HEIGHT * width)) {
-               scale_input_x = (OV9740_MAX_HEIGHT * width) / height;
-               scale_input_y = OV9740_MAX_HEIGHT;
-       } else {
-               scale_input_x = OV9740_MAX_WIDTH;
-               scale_input_y = (OV9740_MAX_WIDTH * height) / width;
-       }
-
-       /* These describe the area of the sensor to use. */
-       x_start = (OV9740_MAX_WIDTH - scale_input_x) / 2;
-       y_start = (OV9740_MAX_HEIGHT - scale_input_y) / 2;
-       x_end = x_start + scale_input_x - 1;
-       y_end = y_start + scale_input_y - 1;
-
-       ret = ov9740_reg_write(client, OV9740_X_ADDR_START_HI, x_start >> 8);
-       if (ret)
-               goto done;
-       ret = ov9740_reg_write(client, OV9740_X_ADDR_START_LO, x_start & 0xff);
-       if (ret)
-               goto done;
-       ret = ov9740_reg_write(client, OV9740_Y_ADDR_START_HI, y_start >> 8);
-       if (ret)
-               goto done;
-       ret = ov9740_reg_write(client, OV9740_Y_ADDR_START_LO, y_start & 0xff);
-       if (ret)
-               goto done;
-
-       ret = ov9740_reg_write(client, OV9740_X_ADDR_END_HI, x_end >> 8);
-       if (ret)
-               goto done;
-       ret = ov9740_reg_write(client, OV9740_X_ADDR_END_LO, x_end & 0xff);
-       if (ret)
-               goto done;
-       ret = ov9740_reg_write(client, OV9740_Y_ADDR_END_HI, y_end >> 8);
-       if (ret)
-               goto done;
-       ret = ov9740_reg_write(client, OV9740_Y_ADDR_END_LO, y_end & 0xff);
-       if (ret)
-               goto done;
-
-       ret = ov9740_reg_write(client, OV9740_X_OUTPUT_SIZE_HI, width >> 8);
-       if (ret)
-               goto done;
-       ret = ov9740_reg_write(client, OV9740_X_OUTPUT_SIZE_LO, width & 0xff);
-       if (ret)
-               goto done;
-       ret = ov9740_reg_write(client, OV9740_Y_OUTPUT_SIZE_HI, height >> 8);
-       if (ret)
-               goto done;
-       ret = ov9740_reg_write(client, OV9740_Y_OUTPUT_SIZE_LO, height & 0xff);
-       if (ret)
-               goto done;
-
-       ret = ov9740_reg_write(client, OV9740_ISP_CTRL1E, scale_input_x >> 8);
-       if (ret)
-               goto done;
-       ret = ov9740_reg_write(client, OV9740_ISP_CTRL1F, scale_input_x & 0xff);
-       if (ret)
-               goto done;
-       ret = ov9740_reg_write(client, OV9740_ISP_CTRL20, scale_input_y >> 8);
-       if (ret)
-               goto done;
-       ret = ov9740_reg_write(client, OV9740_ISP_CTRL21, scale_input_y & 0xff);
-       if (ret)
-               goto done;
-
-       ret = ov9740_reg_write(client, OV9740_VFIFO_READ_START_HI,
-                              (scale_input_x - width) >> 8);
-       if (ret)
-               goto done;
-       ret = ov9740_reg_write(client, OV9740_VFIFO_READ_START_LO,
-                              (scale_input_x - width) & 0xff);
-       if (ret)
-               goto done;
-
-       ret = ov9740_reg_write(client, OV9740_ISP_CTRL00, 0xff);
-       if (ret)
-               goto done;
-       ret = ov9740_reg_write(client, OV9740_ISP_CTRL01, 0xef |
-                                                         (scaling << 4));
-       if (ret)
-               goto done;
-       ret = ov9740_reg_write(client, OV9740_ISP_CTRL03, 0xff);
-
-done:
-       return ret;
-}
-
-/* set the format we will capture in */
-static int ov9740_s_fmt(struct v4l2_subdev *sd,
-                       struct v4l2_mbus_framefmt *mf)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct ov9740_priv *priv = to_ov9740(sd);
-       int ret;
-
-       ret = ov9740_reg_write_array(client, ov9740_defaults,
-                                    ARRAY_SIZE(ov9740_defaults));
-       if (ret < 0)
-               return ret;
-
-       ret = ov9740_set_res(client, mf->width, mf->height);
-       if (ret < 0)
-               return ret;
-
-       priv->current_mf = *mf;
-       return ret;
-}
-
-static int ov9740_set_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_format *format)
-{
-       struct v4l2_mbus_framefmt *mf = &format->format;
-
-       if (format->pad)
-               return -EINVAL;
-
-       ov9740_res_roundup(&mf->width, &mf->height);
-
-       mf->field = V4L2_FIELD_NONE;
-       mf->code = MEDIA_BUS_FMT_YUYV8_2X8;
-       mf->colorspace = V4L2_COLORSPACE_SRGB;
-
-       if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
-               return ov9740_s_fmt(sd, mf);
-       cfg->try_fmt = *mf;
-       return 0;
-}
-
-static int ov9740_enum_mbus_code(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_mbus_code_enum *code)
-{
-       if (code->pad || code->index >= ARRAY_SIZE(ov9740_codes))
-               return -EINVAL;
-
-       code->code = ov9740_codes[code->index];
-
-       return 0;
-}
-
-static int ov9740_get_selection(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_selection *sel)
-{
-       if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
-               return -EINVAL;
-
-       switch (sel->target) {
-       case V4L2_SEL_TGT_CROP_BOUNDS:
-       case V4L2_SEL_TGT_CROP:
-               sel->r.left = 0;
-               sel->r.top = 0;
-               sel->r.width = OV9740_MAX_WIDTH;
-               sel->r.height = OV9740_MAX_HEIGHT;
-               return 0;
-       default:
-               return -EINVAL;
-       }
-}
-
-/* Set status of additional camera capabilities */
-static int ov9740_s_ctrl(struct v4l2_ctrl *ctrl)
-{
-       struct ov9740_priv *priv =
-               container_of(ctrl->handler, struct ov9740_priv, hdl);
-
-       switch (ctrl->id) {
-       case V4L2_CID_VFLIP:
-               priv->flag_vflip = ctrl->val;
-               break;
-       case V4L2_CID_HFLIP:
-               priv->flag_hflip = ctrl->val;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int ov9740_s_power(struct v4l2_subdev *sd, int on)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
-       struct ov9740_priv *priv = to_ov9740(sd);
-       int ret;
-
-       if (on) {
-               ret = soc_camera_power_on(&client->dev, ssdd, priv->clk);
-               if (ret < 0)
-                       return ret;
-
-               if (priv->current_enable) {
-                       ov9740_s_fmt(sd, &priv->current_mf);
-                       ov9740_s_stream(sd, 1);
-               }
-       } else {
-               if (priv->current_enable) {
-                       ov9740_s_stream(sd, 0);
-                       priv->current_enable = true;
-               }
-
-               soc_camera_power_off(&client->dev, ssdd, priv->clk);
-       }
-
-       return 0;
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int ov9740_get_register(struct v4l2_subdev *sd,
-                              struct v4l2_dbg_register *reg)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret;
-       u8 val;
-
-       if (reg->reg & ~0xffff)
-               return -EINVAL;
-
-       reg->size = 2;
-
-       ret = ov9740_reg_read(client, reg->reg, &val);
-       if (ret)
-               return ret;
-
-       reg->val = (__u64)val;
-
-       return ret;
-}
-
-static int ov9740_set_register(struct v4l2_subdev *sd,
-                              const struct v4l2_dbg_register *reg)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (reg->reg & ~0xffff || reg->val & ~0xff)
-               return -EINVAL;
-
-       return ov9740_reg_write(client, reg->reg, reg->val);
-}
-#endif
-
-static int ov9740_video_probe(struct i2c_client *client)
-{
-       struct v4l2_subdev *sd = i2c_get_clientdata(client);
-       struct ov9740_priv *priv = to_ov9740(sd);
-       u8 modelhi, modello;
-       int ret;
-
-       ret = ov9740_s_power(&priv->subdev, 1);
-       if (ret < 0)
-               return ret;
-
-       /*
-        * check and show product ID and manufacturer ID
-        */
-       ret = ov9740_reg_read(client, OV9740_MODEL_ID_HI, &modelhi);
-       if (ret < 0)
-               goto done;
-
-       ret = ov9740_reg_read(client, OV9740_MODEL_ID_LO, &modello);
-       if (ret < 0)
-               goto done;
-
-       priv->model = (modelhi << 8) | modello;
-
-       ret = ov9740_reg_read(client, OV9740_REVISION_NUMBER, &priv->revision);
-       if (ret < 0)
-               goto done;
-
-       ret = ov9740_reg_read(client, OV9740_MANUFACTURER_ID, &priv->manid);
-       if (ret < 0)
-               goto done;
-
-       ret = ov9740_reg_read(client, OV9740_SMIA_VERSION, &priv->smiaver);
-       if (ret < 0)
-               goto done;
-
-       if (priv->model != 0x9740) {
-               ret = -ENODEV;
-               goto done;
-       }
-
-       dev_info(&client->dev, "ov9740 Model ID 0x%04x, Revision 0x%02x, Manufacturer 0x%02x, SMIA Version 0x%02x\n",
-                priv->model, priv->revision, priv->manid, priv->smiaver);
-
-       ret = v4l2_ctrl_handler_setup(&priv->hdl);
-
-done:
-       ov9740_s_power(&priv->subdev, 0);
-       return ret;
-}
-
-/* Request bus settings on camera side */
-static int ov9740_g_mbus_config(struct v4l2_subdev *sd,
-                               struct v4l2_mbus_config *cfg)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
-
-       cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
-               V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
-               V4L2_MBUS_DATA_ACTIVE_HIGH;
-       cfg->type = V4L2_MBUS_PARALLEL;
-       cfg->flags = soc_camera_apply_board_flags(ssdd, cfg);
-
-       return 0;
-}
-
-static const struct v4l2_subdev_video_ops ov9740_video_ops = {
-       .s_stream       = ov9740_s_stream,
-       .g_mbus_config  = ov9740_g_mbus_config,
-};
-
-static const struct v4l2_subdev_core_ops ov9740_core_ops = {
-       .s_power                = ov9740_s_power,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       .g_register             = ov9740_get_register,
-       .s_register             = ov9740_set_register,
-#endif
-};
-
-static const struct v4l2_subdev_pad_ops ov9740_pad_ops = {
-       .enum_mbus_code = ov9740_enum_mbus_code,
-       .get_selection  = ov9740_get_selection,
-       .set_fmt        = ov9740_set_fmt,
-};
-
-static const struct v4l2_subdev_ops ov9740_subdev_ops = {
-       .core   = &ov9740_core_ops,
-       .video  = &ov9740_video_ops,
-       .pad    = &ov9740_pad_ops,
-};
-
-static const struct v4l2_ctrl_ops ov9740_ctrl_ops = {
-       .s_ctrl = ov9740_s_ctrl,
-};
-
-/*
- * i2c_driver function
- */
-static int ov9740_probe(struct i2c_client *client,
-                       const struct i2c_device_id *did)
-{
-       struct ov9740_priv *priv;
-       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
-       int ret;
-
-       if (!ssdd) {
-               dev_err(&client->dev, "Missing platform_data for driver\n");
-               return -EINVAL;
-       }
-
-       priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-
-       v4l2_i2c_subdev_init(&priv->subdev, client, &ov9740_subdev_ops);
-       v4l2_ctrl_handler_init(&priv->hdl, 13);
-       v4l2_ctrl_new_std(&priv->hdl, &ov9740_ctrl_ops,
-                       V4L2_CID_VFLIP, 0, 1, 1, 0);
-       v4l2_ctrl_new_std(&priv->hdl, &ov9740_ctrl_ops,
-                       V4L2_CID_HFLIP, 0, 1, 1, 0);
-       priv->subdev.ctrl_handler = &priv->hdl;
-       if (priv->hdl.error)
-               return priv->hdl.error;
-
-       priv->clk = v4l2_clk_get(&client->dev, "mclk");
-       if (IS_ERR(priv->clk)) {
-               ret = PTR_ERR(priv->clk);
-               goto eclkget;
-       }
-
-       ret = ov9740_video_probe(client);
-       if (ret < 0) {
-               v4l2_clk_put(priv->clk);
-eclkget:
-               v4l2_ctrl_handler_free(&priv->hdl);
-       }
-
-       return ret;
-}
-
-static int ov9740_remove(struct i2c_client *client)
-{
-       struct ov9740_priv *priv = i2c_get_clientdata(client);
-
-       v4l2_clk_put(priv->clk);
-       v4l2_device_unregister_subdev(&priv->subdev);
-       v4l2_ctrl_handler_free(&priv->hdl);
-       return 0;
-}
-
-static const struct i2c_device_id ov9740_id[] = {
-       { "ov9740", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, ov9740_id);
-
-static struct i2c_driver ov9740_i2c_driver = {
-       .driver = {
-               .name = "ov9740",
-       },
-       .probe    = ov9740_probe,
-       .remove   = ov9740_remove,
-       .id_table = ov9740_id,
-};
-
-module_i2c_driver(ov9740_i2c_driver);
-
-MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV9740");
-MODULE_AUTHOR("Andrew Chew <achew@nvidia.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/soc_camera/rj54n1cb0c.c b/drivers/media/i2c/soc_camera/rj54n1cb0c.c
deleted file mode 100644 (file)
index f0cb49a..0000000
+++ /dev/null
@@ -1,1415 +0,0 @@
-/*
- * Driver for RJ54N1CB0C CMOS Image Sensor from Sharp
- *
- * Copyright (C) 2009, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- *
- * 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.
- */
-
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/v4l2-mediabus.h>
-#include <linux/videodev2.h>
-#include <linux/module.h>
-
-#include <media/i2c/rj54n1cb0c.h>
-#include <media/soc_camera.h>
-#include <media/v4l2-clk.h>
-#include <media/v4l2-subdev.h>
-#include <media/v4l2-ctrls.h>
-
-#define RJ54N1_DEV_CODE                        0x0400
-#define RJ54N1_DEV_CODE2               0x0401
-#define RJ54N1_OUT_SEL                 0x0403
-#define RJ54N1_XY_OUTPUT_SIZE_S_H      0x0404
-#define RJ54N1_X_OUTPUT_SIZE_S_L       0x0405
-#define RJ54N1_Y_OUTPUT_SIZE_S_L       0x0406
-#define RJ54N1_XY_OUTPUT_SIZE_P_H      0x0407
-#define RJ54N1_X_OUTPUT_SIZE_P_L       0x0408
-#define RJ54N1_Y_OUTPUT_SIZE_P_L       0x0409
-#define RJ54N1_LINE_LENGTH_PCK_S_H     0x040a
-#define RJ54N1_LINE_LENGTH_PCK_S_L     0x040b
-#define RJ54N1_LINE_LENGTH_PCK_P_H     0x040c
-#define RJ54N1_LINE_LENGTH_PCK_P_L     0x040d
-#define RJ54N1_RESIZE_N                        0x040e
-#define RJ54N1_RESIZE_N_STEP           0x040f
-#define RJ54N1_RESIZE_STEP             0x0410
-#define RJ54N1_RESIZE_HOLD_H           0x0411
-#define RJ54N1_RESIZE_HOLD_L           0x0412
-#define RJ54N1_H_OBEN_OFS              0x0413
-#define RJ54N1_V_OBEN_OFS              0x0414
-#define RJ54N1_RESIZE_CONTROL          0x0415
-#define RJ54N1_STILL_CONTROL           0x0417
-#define RJ54N1_INC_USE_SEL_H           0x0425
-#define RJ54N1_INC_USE_SEL_L           0x0426
-#define RJ54N1_MIRROR_STILL_MODE       0x0427
-#define RJ54N1_INIT_START              0x0428
-#define RJ54N1_SCALE_1_2_LEV           0x0429
-#define RJ54N1_SCALE_4_LEV             0x042a
-#define RJ54N1_Y_GAIN                  0x04d8
-#define RJ54N1_APT_GAIN_UP             0x04fa
-#define RJ54N1_RA_SEL_UL               0x0530
-#define RJ54N1_BYTE_SWAP               0x0531
-#define RJ54N1_OUT_SIGPO               0x053b
-#define RJ54N1_WB_SEL_WEIGHT_I         0x054e
-#define RJ54N1_BIT8_WB                 0x0569
-#define RJ54N1_HCAPS_WB                        0x056a
-#define RJ54N1_VCAPS_WB                        0x056b
-#define RJ54N1_HCAPE_WB                        0x056c
-#define RJ54N1_VCAPE_WB                        0x056d
-#define RJ54N1_EXPOSURE_CONTROL                0x058c
-#define RJ54N1_FRAME_LENGTH_S_H                0x0595
-#define RJ54N1_FRAME_LENGTH_S_L                0x0596
-#define RJ54N1_FRAME_LENGTH_P_H                0x0597
-#define RJ54N1_FRAME_LENGTH_P_L                0x0598
-#define RJ54N1_PEAK_H                  0x05b7
-#define RJ54N1_PEAK_50                 0x05b8
-#define RJ54N1_PEAK_60                 0x05b9
-#define RJ54N1_PEAK_DIFF               0x05ba
-#define RJ54N1_IOC                     0x05ef
-#define RJ54N1_TG_BYPASS               0x0700
-#define RJ54N1_PLL_L                   0x0701
-#define RJ54N1_PLL_N                   0x0702
-#define RJ54N1_PLL_EN                  0x0704
-#define RJ54N1_RATIO_TG                        0x0706
-#define RJ54N1_RATIO_T                 0x0707
-#define RJ54N1_RATIO_R                 0x0708
-#define RJ54N1_RAMP_TGCLK_EN           0x0709
-#define RJ54N1_OCLK_DSP                        0x0710
-#define RJ54N1_RATIO_OP                        0x0711
-#define RJ54N1_RATIO_O                 0x0712
-#define RJ54N1_OCLK_SEL_EN             0x0713
-#define RJ54N1_CLK_RST                 0x0717
-#define RJ54N1_RESET_STANDBY           0x0718
-#define RJ54N1_FWFLG                   0x07fe
-
-#define E_EXCLK                                (1 << 7)
-#define SOFT_STDBY                     (1 << 4)
-#define SEN_RSTX                       (1 << 2)
-#define TG_RSTX                                (1 << 1)
-#define DSP_RSTX                       (1 << 0)
-
-#define RESIZE_HOLD_SEL                        (1 << 2)
-#define RESIZE_GO                      (1 << 1)
-
-/*
- * When cropping, the camera automatically centers the cropped region, there
- * doesn't seem to be a way to specify an explicit location of the rectangle.
- */
-#define RJ54N1_COLUMN_SKIP             0
-#define RJ54N1_ROW_SKIP                        0
-#define RJ54N1_MAX_WIDTH               1600
-#define RJ54N1_MAX_HEIGHT              1200
-
-#define PLL_L                          2
-#define PLL_N                          0x31
-
-/* I2C addresses: 0x50, 0x51, 0x60, 0x61 */
-
-/* RJ54N1CB0C has only one fixed colorspace per pixelcode */
-struct rj54n1_datafmt {
-       u32     code;
-       enum v4l2_colorspace            colorspace;
-};
-
-/* Find a data format by a pixel code in an array */
-static const struct rj54n1_datafmt *rj54n1_find_datafmt(
-       u32 code, const struct rj54n1_datafmt *fmt,
-       int n)
-{
-       int i;
-       for (i = 0; i < n; i++)
-               if (fmt[i].code == code)
-                       return fmt + i;
-
-       return NULL;
-}
-
-static const struct rj54n1_datafmt rj54n1_colour_fmts[] = {
-       {MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG},
-       {MEDIA_BUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG},
-       {MEDIA_BUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB},
-       {MEDIA_BUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB},
-       {MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
-       {MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE, V4L2_COLORSPACE_SRGB},
-       {MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE, V4L2_COLORSPACE_SRGB},
-       {MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE, V4L2_COLORSPACE_SRGB},
-       {MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB},
-};
-
-struct rj54n1_clock_div {
-       u8 ratio_tg;    /* can be 0 or an odd number */
-       u8 ratio_t;
-       u8 ratio_r;
-       u8 ratio_op;
-       u8 ratio_o;
-};
-
-struct rj54n1 {
-       struct v4l2_subdev subdev;
-       struct v4l2_ctrl_handler hdl;
-       struct v4l2_clk *clk;
-       struct rj54n1_clock_div clk_div;
-       const struct rj54n1_datafmt *fmt;
-       struct v4l2_rect rect;  /* Sensor window */
-       unsigned int tgclk_mhz;
-       bool auto_wb;
-       unsigned short width;   /* Output window */
-       unsigned short height;
-       unsigned short resize;  /* Sensor * 1024 / resize = Output */
-       unsigned short scale;
-       u8 bank;
-};
-
-struct rj54n1_reg_val {
-       u16 reg;
-       u8 val;
-};
-
-static const struct rj54n1_reg_val bank_4[] = {
-       {0x417, 0},
-       {0x42c, 0},
-       {0x42d, 0xf0},
-       {0x42e, 0},
-       {0x42f, 0x50},
-       {0x430, 0xf5},
-       {0x431, 0x16},
-       {0x432, 0x20},
-       {0x433, 0},
-       {0x434, 0xc8},
-       {0x43c, 8},
-       {0x43e, 0x90},
-       {0x445, 0x83},
-       {0x4ba, 0x58},
-       {0x4bb, 4},
-       {0x4bc, 0x20},
-       {0x4db, 4},
-       {0x4fe, 2},
-};
-
-static const struct rj54n1_reg_val bank_5[] = {
-       {0x514, 0},
-       {0x516, 0},
-       {0x518, 0},
-       {0x51a, 0},
-       {0x51d, 0xff},
-       {0x56f, 0x28},
-       {0x575, 0x40},
-       {0x5bc, 0x48},
-       {0x5c1, 6},
-       {0x5e5, 0x11},
-       {0x5e6, 0x43},
-       {0x5e7, 0x33},
-       {0x5e8, 0x21},
-       {0x5e9, 0x30},
-       {0x5ea, 0x0},
-       {0x5eb, 0xa5},
-       {0x5ec, 0xff},
-       {0x5fe, 2},
-};
-
-static const struct rj54n1_reg_val bank_7[] = {
-       {0x70a, 0},
-       {0x714, 0xff},
-       {0x715, 0xff},
-       {0x716, 0x1f},
-       {0x7FE, 2},
-};
-
-static const struct rj54n1_reg_val bank_8[] = {
-       {0x800, 0x00},
-       {0x801, 0x01},
-       {0x802, 0x61},
-       {0x805, 0x00},
-       {0x806, 0x00},
-       {0x807, 0x00},
-       {0x808, 0x00},
-       {0x809, 0x01},
-       {0x80A, 0x61},
-       {0x80B, 0x00},
-       {0x80C, 0x01},
-       {0x80D, 0x00},
-       {0x80E, 0x00},
-       {0x80F, 0x00},
-       {0x810, 0x00},
-       {0x811, 0x01},
-       {0x812, 0x61},
-       {0x813, 0x00},
-       {0x814, 0x11},
-       {0x815, 0x00},
-       {0x816, 0x41},
-       {0x817, 0x00},
-       {0x818, 0x51},
-       {0x819, 0x01},
-       {0x81A, 0x1F},
-       {0x81B, 0x00},
-       {0x81C, 0x01},
-       {0x81D, 0x00},
-       {0x81E, 0x11},
-       {0x81F, 0x00},
-       {0x820, 0x41},
-       {0x821, 0x00},
-       {0x822, 0x51},
-       {0x823, 0x00},
-       {0x824, 0x00},
-       {0x825, 0x00},
-       {0x826, 0x47},
-       {0x827, 0x01},
-       {0x828, 0x4F},
-       {0x829, 0x00},
-       {0x82A, 0x00},
-       {0x82B, 0x00},
-       {0x82C, 0x30},
-       {0x82D, 0x00},
-       {0x82E, 0x40},
-       {0x82F, 0x00},
-       {0x830, 0xB3},
-       {0x831, 0x00},
-       {0x832, 0xE3},
-       {0x833, 0x00},
-       {0x834, 0x00},
-       {0x835, 0x00},
-       {0x836, 0x00},
-       {0x837, 0x00},
-       {0x838, 0x00},
-       {0x839, 0x01},
-       {0x83A, 0x61},
-       {0x83B, 0x00},
-       {0x83C, 0x01},
-       {0x83D, 0x00},
-       {0x83E, 0x00},
-       {0x83F, 0x00},
-       {0x840, 0x00},
-       {0x841, 0x01},
-       {0x842, 0x61},
-       {0x843, 0x00},
-       {0x844, 0x1D},
-       {0x845, 0x00},
-       {0x846, 0x00},
-       {0x847, 0x00},
-       {0x848, 0x00},
-       {0x849, 0x01},
-       {0x84A, 0x1F},
-       {0x84B, 0x00},
-       {0x84C, 0x05},
-       {0x84D, 0x00},
-       {0x84E, 0x19},
-       {0x84F, 0x01},
-       {0x850, 0x21},
-       {0x851, 0x01},
-       {0x852, 0x5D},
-       {0x853, 0x00},
-       {0x854, 0x00},
-       {0x855, 0x00},
-       {0x856, 0x19},
-       {0x857, 0x01},
-       {0x858, 0x21},
-       {0x859, 0x00},
-       {0x85A, 0x00},
-       {0x85B, 0x00},
-       {0x85C, 0x00},
-       {0x85D, 0x00},
-       {0x85E, 0x00},
-       {0x85F, 0x00},
-       {0x860, 0xB3},
-       {0x861, 0x00},
-       {0x862, 0xE3},
-       {0x863, 0x00},
-       {0x864, 0x00},
-       {0x865, 0x00},
-       {0x866, 0x00},
-       {0x867, 0x00},
-       {0x868, 0x00},
-       {0x869, 0xE2},
-       {0x86A, 0x00},
-       {0x86B, 0x01},
-       {0x86C, 0x06},
-       {0x86D, 0x00},
-       {0x86E, 0x00},
-       {0x86F, 0x00},
-       {0x870, 0x60},
-       {0x871, 0x8C},
-       {0x872, 0x10},
-       {0x873, 0x00},
-       {0x874, 0xE0},
-       {0x875, 0x00},
-       {0x876, 0x27},
-       {0x877, 0x01},
-       {0x878, 0x00},
-       {0x879, 0x00},
-       {0x87A, 0x00},
-       {0x87B, 0x03},
-       {0x87C, 0x00},
-       {0x87D, 0x00},
-       {0x87E, 0x00},
-       {0x87F, 0x00},
-       {0x880, 0x00},
-       {0x881, 0x00},
-       {0x882, 0x00},
-       {0x883, 0x00},
-       {0x884, 0x00},
-       {0x885, 0x00},
-       {0x886, 0xF8},
-       {0x887, 0x00},
-       {0x888, 0x03},
-       {0x889, 0x00},
-       {0x88A, 0x64},
-       {0x88B, 0x00},
-       {0x88C, 0x03},
-       {0x88D, 0x00},
-       {0x88E, 0xB1},
-       {0x88F, 0x00},
-       {0x890, 0x03},
-       {0x891, 0x01},
-       {0x892, 0x1D},
-       {0x893, 0x00},
-       {0x894, 0x03},
-       {0x895, 0x01},
-       {0x896, 0x4B},
-       {0x897, 0x00},
-       {0x898, 0xE5},
-       {0x899, 0x00},
-       {0x89A, 0x01},
-       {0x89B, 0x00},
-       {0x89C, 0x01},
-       {0x89D, 0x04},
-       {0x89E, 0xC8},
-       {0x89F, 0x00},
-       {0x8A0, 0x01},
-       {0x8A1, 0x01},
-       {0x8A2, 0x61},
-       {0x8A3, 0x00},
-       {0x8A4, 0x01},
-       {0x8A5, 0x00},
-       {0x8A6, 0x00},
-       {0x8A7, 0x00},
-       {0x8A8, 0x00},
-       {0x8A9, 0x00},
-       {0x8AA, 0x7F},
-       {0x8AB, 0x03},
-       {0x8AC, 0x00},
-       {0x8AD, 0x00},
-       {0x8AE, 0x00},
-       {0x8AF, 0x00},
-       {0x8B0, 0x00},
-       {0x8B1, 0x00},
-       {0x8B6, 0x00},
-       {0x8B7, 0x01},
-       {0x8B8, 0x00},
-       {0x8B9, 0x00},
-       {0x8BA, 0x02},
-       {0x8BB, 0x00},
-       {0x8BC, 0xFF},
-       {0x8BD, 0x00},
-       {0x8FE, 2},
-};
-
-static const struct rj54n1_reg_val bank_10[] = {
-       {0x10bf, 0x69}
-};
-
-/* Clock dividers - these are default register values, divider = register + 1 */
-static const struct rj54n1_clock_div clk_div = {
-       .ratio_tg       = 3 /* default: 5 */,
-       .ratio_t        = 4 /* default: 1 */,
-       .ratio_r        = 4 /* default: 0 */,
-       .ratio_op       = 1 /* default: 5 */,
-       .ratio_o        = 9 /* default: 0 */,
-};
-
-static struct rj54n1 *to_rj54n1(const struct i2c_client *client)
-{
-       return container_of(i2c_get_clientdata(client), struct rj54n1, subdev);
-}
-
-static int reg_read(struct i2c_client *client, const u16 reg)
-{
-       struct rj54n1 *rj54n1 = to_rj54n1(client);
-       int ret;
-
-       /* set bank */
-       if (rj54n1->bank != reg >> 8) {
-               dev_dbg(&client->dev, "[0x%x] = 0x%x\n", 0xff, reg >> 8);
-               ret = i2c_smbus_write_byte_data(client, 0xff, reg >> 8);
-               if (ret < 0)
-                       return ret;
-               rj54n1->bank = reg >> 8;
-       }
-       return i2c_smbus_read_byte_data(client, reg & 0xff);
-}
-
-static int reg_write(struct i2c_client *client, const u16 reg,
-                    const u8 data)
-{
-       struct rj54n1 *rj54n1 = to_rj54n1(client);
-       int ret;
-
-       /* set bank */
-       if (rj54n1->bank != reg >> 8) {
-               dev_dbg(&client->dev, "[0x%x] = 0x%x\n", 0xff, reg >> 8);
-               ret = i2c_smbus_write_byte_data(client, 0xff, reg >> 8);
-               if (ret < 0)
-                       return ret;
-               rj54n1->bank = reg >> 8;
-       }
-       dev_dbg(&client->dev, "[0x%x] = 0x%x\n", reg & 0xff, data);
-       return i2c_smbus_write_byte_data(client, reg & 0xff, data);
-}
-
-static int reg_set(struct i2c_client *client, const u16 reg,
-                  const u8 data, const u8 mask)
-{
-       int ret;
-
-       ret = reg_read(client, reg);
-       if (ret < 0)
-               return ret;
-       return reg_write(client, reg, (ret & ~mask) | (data & mask));
-}
-
-static int reg_write_multiple(struct i2c_client *client,
-                             const struct rj54n1_reg_val *rv, const int n)
-{
-       int i, ret;
-
-       for (i = 0; i < n; i++) {
-               ret = reg_write(client, rv->reg, rv->val);
-               if (ret < 0)
-                       return ret;
-               rv++;
-       }
-
-       return 0;
-}
-
-static int rj54n1_enum_mbus_code(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_mbus_code_enum *code)
-{
-       if (code->pad || code->index >= ARRAY_SIZE(rj54n1_colour_fmts))
-               return -EINVAL;
-
-       code->code = rj54n1_colour_fmts[code->index].code;
-       return 0;
-}
-
-static int rj54n1_s_stream(struct v4l2_subdev *sd, int enable)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       /* Switch between preview and still shot modes */
-       return reg_set(client, RJ54N1_STILL_CONTROL, (!enable) << 7, 0x80);
-}
-
-static int rj54n1_set_rect(struct i2c_client *client,
-                          u16 reg_x, u16 reg_y, u16 reg_xy,
-                          u32 width, u32 height)
-{
-       int ret;
-
-       ret = reg_write(client, reg_xy,
-                       ((width >> 4) & 0x70) |
-                       ((height >> 8) & 7));
-
-       if (!ret)
-               ret = reg_write(client, reg_x, width & 0xff);
-       if (!ret)
-               ret = reg_write(client, reg_y, height & 0xff);
-
-       return ret;
-}
-
-/*
- * Some commands, specifically certain initialisation sequences, require
- * a commit operation.
- */
-static int rj54n1_commit(struct i2c_client *client)
-{
-       int ret = reg_write(client, RJ54N1_INIT_START, 1);
-       msleep(10);
-       if (!ret)
-               ret = reg_write(client, RJ54N1_INIT_START, 0);
-       return ret;
-}
-
-static int rj54n1_sensor_scale(struct v4l2_subdev *sd, s32 *in_w, s32 *in_h,
-                              s32 *out_w, s32 *out_h);
-
-static int rj54n1_set_selection(struct v4l2_subdev *sd,
-                               struct v4l2_subdev_pad_config *cfg,
-                               struct v4l2_subdev_selection *sel)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct rj54n1 *rj54n1 = to_rj54n1(client);
-       const struct v4l2_rect *rect = &sel->r;
-       int dummy = 0, output_w, output_h,
-               input_w = rect->width, input_h = rect->height;
-       int ret;
-
-       if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
-           sel->target != V4L2_SEL_TGT_CROP)
-               return -EINVAL;
-
-       /* arbitrary minimum width and height, edges unimportant */
-       soc_camera_limit_side(&dummy, &input_w,
-                    RJ54N1_COLUMN_SKIP, 8, RJ54N1_MAX_WIDTH);
-
-       soc_camera_limit_side(&dummy, &input_h,
-                    RJ54N1_ROW_SKIP, 8, RJ54N1_MAX_HEIGHT);
-
-       output_w = (input_w * 1024 + rj54n1->resize / 2) / rj54n1->resize;
-       output_h = (input_h * 1024 + rj54n1->resize / 2) / rj54n1->resize;
-
-       dev_dbg(&client->dev, "Scaling for %dx%d : %u = %dx%d\n",
-               input_w, input_h, rj54n1->resize, output_w, output_h);
-
-       ret = rj54n1_sensor_scale(sd, &input_w, &input_h, &output_w, &output_h);
-       if (ret < 0)
-               return ret;
-
-       rj54n1->width           = output_w;
-       rj54n1->height          = output_h;
-       rj54n1->resize          = ret;
-       rj54n1->rect.width      = input_w;
-       rj54n1->rect.height     = input_h;
-
-       return 0;
-}
-
-static int rj54n1_get_selection(struct v4l2_subdev *sd,
-                               struct v4l2_subdev_pad_config *cfg,
-                               struct v4l2_subdev_selection *sel)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct rj54n1 *rj54n1 = to_rj54n1(client);
-
-       if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
-               return -EINVAL;
-
-       switch (sel->target) {
-       case V4L2_SEL_TGT_CROP_BOUNDS:
-               sel->r.left = RJ54N1_COLUMN_SKIP;
-               sel->r.top = RJ54N1_ROW_SKIP;
-               sel->r.width = RJ54N1_MAX_WIDTH;
-               sel->r.height = RJ54N1_MAX_HEIGHT;
-               return 0;
-       case V4L2_SEL_TGT_CROP:
-               sel->r = rj54n1->rect;
-               return 0;
-       default:
-               return -EINVAL;
-       }
-}
-
-static int rj54n1_get_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_format *format)
-{
-       struct v4l2_mbus_framefmt *mf = &format->format;
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct rj54n1 *rj54n1 = to_rj54n1(client);
-
-       if (format->pad)
-               return -EINVAL;
-
-       mf->code        = rj54n1->fmt->code;
-       mf->colorspace  = rj54n1->fmt->colorspace;
-       mf->field       = V4L2_FIELD_NONE;
-       mf->width       = rj54n1->width;
-       mf->height      = rj54n1->height;
-
-       return 0;
-}
-
-/*
- * The actual geometry configuration routine. It scales the input window into
- * the output one, updates the window sizes and returns an error or the resize
- * coefficient on success. Note: we only use the "Fixed Scaling" on this camera.
- */
-static int rj54n1_sensor_scale(struct v4l2_subdev *sd, s32 *in_w, s32 *in_h,
-                              s32 *out_w, s32 *out_h)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct rj54n1 *rj54n1 = to_rj54n1(client);
-       unsigned int skip, resize, input_w = *in_w, input_h = *in_h,
-               output_w = *out_w, output_h = *out_h;
-       u16 inc_sel, wb_bit8, wb_left, wb_right, wb_top, wb_bottom;
-       unsigned int peak, peak_50, peak_60;
-       int ret;
-
-       /*
-        * We have a problem with crops, where the window is larger than 512x384
-        * and output window is larger than a half of the input one. In this
-        * case we have to either reduce the input window to equal or below
-        * 512x384 or the output window to equal or below 1/2 of the input.
-        */
-       if (output_w > max(512U, input_w / 2)) {
-               if (2 * output_w > RJ54N1_MAX_WIDTH) {
-                       input_w = RJ54N1_MAX_WIDTH;
-                       output_w = RJ54N1_MAX_WIDTH / 2;
-               } else {
-                       input_w = output_w * 2;
-               }
-
-               dev_dbg(&client->dev, "Adjusted output width: in %u, out %u\n",
-                       input_w, output_w);
-       }
-
-       if (output_h > max(384U, input_h / 2)) {
-               if (2 * output_h > RJ54N1_MAX_HEIGHT) {
-                       input_h = RJ54N1_MAX_HEIGHT;
-                       output_h = RJ54N1_MAX_HEIGHT / 2;
-               } else {
-                       input_h = output_h * 2;
-               }
-
-               dev_dbg(&client->dev, "Adjusted output height: in %u, out %u\n",
-                       input_h, output_h);
-       }
-
-       /* Idea: use the read mode for snapshots, handle separate geometries */
-       ret = rj54n1_set_rect(client, RJ54N1_X_OUTPUT_SIZE_S_L,
-                             RJ54N1_Y_OUTPUT_SIZE_S_L,
-                             RJ54N1_XY_OUTPUT_SIZE_S_H, output_w, output_h);
-       if (!ret)
-               ret = rj54n1_set_rect(client, RJ54N1_X_OUTPUT_SIZE_P_L,
-                             RJ54N1_Y_OUTPUT_SIZE_P_L,
-                             RJ54N1_XY_OUTPUT_SIZE_P_H, output_w, output_h);
-
-       if (ret < 0)
-               return ret;
-
-       if (output_w > input_w && output_h > input_h) {
-               input_w = output_w;
-               input_h = output_h;
-
-               resize = 1024;
-       } else {
-               unsigned int resize_x, resize_y;
-               resize_x = (input_w * 1024 + output_w / 2) / output_w;
-               resize_y = (input_h * 1024 + output_h / 2) / output_h;
-
-               /* We want max(resize_x, resize_y), check if it still fits */
-               if (resize_x > resize_y &&
-                   (output_h * resize_x + 512) / 1024 > RJ54N1_MAX_HEIGHT)
-                       resize = (RJ54N1_MAX_HEIGHT * 1024 + output_h / 2) /
-                               output_h;
-               else if (resize_y > resize_x &&
-                        (output_w * resize_y + 512) / 1024 > RJ54N1_MAX_WIDTH)
-                       resize = (RJ54N1_MAX_WIDTH * 1024 + output_w / 2) /
-                               output_w;
-               else
-                       resize = max(resize_x, resize_y);
-
-               /* Prohibited value ranges */
-               switch (resize) {
-               case 2040 ... 2047:
-                       resize = 2039;
-                       break;
-               case 4080 ... 4095:
-                       resize = 4079;
-                       break;
-               case 8160 ... 8191:
-                       resize = 8159;
-                       break;
-               case 16320 ... 16384:
-                       resize = 16319;
-               }
-       }
-
-       /* Set scaling */
-       ret = reg_write(client, RJ54N1_RESIZE_HOLD_L, resize & 0xff);
-       if (!ret)
-               ret = reg_write(client, RJ54N1_RESIZE_HOLD_H, resize >> 8);
-
-       if (ret < 0)
-               return ret;
-
-       /*
-        * Configure a skipping bitmask. The sensor will select a skipping value
-        * among set bits automatically. This is very unclear in the datasheet
-        * too. I was told, in this register one enables all skipping values,
-        * that are required for a specific resize, and the camera selects
-        * automatically, which ones to use. But it is unclear how to identify,
-        * which cropping values are needed. Secondly, why don't we just set all
-        * bits and let the camera choose? Would it increase processing time and
-        * reduce the framerate? Using 0xfffc for INC_USE_SEL doesn't seem to
-        * improve the image quality or stability for larger frames (see comment
-        * above), but I didn't check the framerate.
-        */
-       skip = min(resize / 1024, 15U);
-
-       inc_sel = 1 << skip;
-
-       if (inc_sel <= 2)
-               inc_sel = 0xc;
-       else if (resize & 1023 && skip < 15)
-               inc_sel |= 1 << (skip + 1);
-
-       ret = reg_write(client, RJ54N1_INC_USE_SEL_L, inc_sel & 0xfc);
-       if (!ret)
-               ret = reg_write(client, RJ54N1_INC_USE_SEL_H, inc_sel >> 8);
-
-       if (!rj54n1->auto_wb) {
-               /* Auto white balance window */
-               wb_left   = output_w / 16;
-               wb_right  = (3 * output_w / 4 - 3) / 4;
-               wb_top    = output_h / 16;
-               wb_bottom = (3 * output_h / 4 - 3) / 4;
-               wb_bit8   = ((wb_left >> 2) & 0x40) | ((wb_top >> 4) & 0x10) |
-                       ((wb_right >> 6) & 4) | ((wb_bottom >> 8) & 1);
-
-               if (!ret)
-                       ret = reg_write(client, RJ54N1_BIT8_WB, wb_bit8);
-               if (!ret)
-                       ret = reg_write(client, RJ54N1_HCAPS_WB, wb_left);
-               if (!ret)
-                       ret = reg_write(client, RJ54N1_VCAPS_WB, wb_top);
-               if (!ret)
-                       ret = reg_write(client, RJ54N1_HCAPE_WB, wb_right);
-               if (!ret)
-                       ret = reg_write(client, RJ54N1_VCAPE_WB, wb_bottom);
-       }
-
-       /* Antiflicker */
-       peak = 12 * RJ54N1_MAX_WIDTH * (1 << 14) * resize / rj54n1->tgclk_mhz /
-               10000;
-       peak_50 = peak / 6;
-       peak_60 = peak / 5;
-
-       if (!ret)
-               ret = reg_write(client, RJ54N1_PEAK_H,
-                               ((peak_50 >> 4) & 0xf0) | (peak_60 >> 8));
-       if (!ret)
-               ret = reg_write(client, RJ54N1_PEAK_50, peak_50);
-       if (!ret)
-               ret = reg_write(client, RJ54N1_PEAK_60, peak_60);
-       if (!ret)
-               ret = reg_write(client, RJ54N1_PEAK_DIFF, peak / 150);
-
-       /* Start resizing */
-       if (!ret)
-               ret = reg_write(client, RJ54N1_RESIZE_CONTROL,
-                               RESIZE_HOLD_SEL | RESIZE_GO | 1);
-
-       if (ret < 0)
-               return ret;
-
-       /* Constant taken from manufacturer's example */
-       msleep(230);
-
-       ret = reg_write(client, RJ54N1_RESIZE_CONTROL, RESIZE_HOLD_SEL | 1);
-       if (ret < 0)
-               return ret;
-
-       *in_w = (output_w * resize + 512) / 1024;
-       *in_h = (output_h * resize + 512) / 1024;
-       *out_w = output_w;
-       *out_h = output_h;
-
-       dev_dbg(&client->dev, "Scaled for %dx%d : %u = %ux%u, skip %u\n",
-               *in_w, *in_h, resize, output_w, output_h, skip);
-
-       return resize;
-}
-
-static int rj54n1_set_clock(struct i2c_client *client)
-{
-       struct rj54n1 *rj54n1 = to_rj54n1(client);
-       int ret;
-
-       /* Enable external clock */
-       ret = reg_write(client, RJ54N1_RESET_STANDBY, E_EXCLK | SOFT_STDBY);
-       /* Leave stand-by. Note: use this when implementing suspend / resume */
-       if (!ret)
-               ret = reg_write(client, RJ54N1_RESET_STANDBY, E_EXCLK);
-
-       if (!ret)
-               ret = reg_write(client, RJ54N1_PLL_L, PLL_L);
-       if (!ret)
-               ret = reg_write(client, RJ54N1_PLL_N, PLL_N);
-
-       /* TGCLK dividers */
-       if (!ret)
-               ret = reg_write(client, RJ54N1_RATIO_TG,
-                               rj54n1->clk_div.ratio_tg);
-       if (!ret)
-               ret = reg_write(client, RJ54N1_RATIO_T,
-                               rj54n1->clk_div.ratio_t);
-       if (!ret)
-               ret = reg_write(client, RJ54N1_RATIO_R,
-                               rj54n1->clk_div.ratio_r);
-
-       /* Enable TGCLK & RAMP */
-       if (!ret)
-               ret = reg_write(client, RJ54N1_RAMP_TGCLK_EN, 3);
-
-       /* Disable clock output */
-       if (!ret)
-               ret = reg_write(client, RJ54N1_OCLK_DSP, 0);
-
-       /* Set divisors */
-       if (!ret)
-               ret = reg_write(client, RJ54N1_RATIO_OP,
-                               rj54n1->clk_div.ratio_op);
-       if (!ret)
-               ret = reg_write(client, RJ54N1_RATIO_O,
-                               rj54n1->clk_div.ratio_o);
-
-       /* Enable OCLK */
-       if (!ret)
-               ret = reg_write(client, RJ54N1_OCLK_SEL_EN, 1);
-
-       /* Use PLL for Timing Generator, write 2 to reserved bits */
-       if (!ret)
-               ret = reg_write(client, RJ54N1_TG_BYPASS, 2);
-
-       /* Take sensor out of reset */
-       if (!ret)
-               ret = reg_write(client, RJ54N1_RESET_STANDBY,
-                               E_EXCLK | SEN_RSTX);
-       /* Enable PLL */
-       if (!ret)
-               ret = reg_write(client, RJ54N1_PLL_EN, 1);
-
-       /* Wait for PLL to stabilise */
-       msleep(10);
-
-       /* Enable clock to frequency divider */
-       if (!ret)
-               ret = reg_write(client, RJ54N1_CLK_RST, 1);
-
-       if (!ret)
-               ret = reg_read(client, RJ54N1_CLK_RST);
-       if (ret != 1) {
-               dev_err(&client->dev,
-                       "Resetting RJ54N1CB0C clock failed: %d!\n", ret);
-               return -EIO;
-       }
-
-       /* Start the PLL */
-       ret = reg_set(client, RJ54N1_OCLK_DSP, 1, 1);
-
-       /* Enable OCLK */
-       if (!ret)
-               ret = reg_write(client, RJ54N1_OCLK_SEL_EN, 1);
-
-       return ret;
-}
-
-static int rj54n1_reg_init(struct i2c_client *client)
-{
-       struct rj54n1 *rj54n1 = to_rj54n1(client);
-       int ret = rj54n1_set_clock(client);
-
-       if (!ret)
-               ret = reg_write_multiple(client, bank_7, ARRAY_SIZE(bank_7));
-       if (!ret)
-               ret = reg_write_multiple(client, bank_10, ARRAY_SIZE(bank_10));
-
-       /* Set binning divisors */
-       if (!ret)
-               ret = reg_write(client, RJ54N1_SCALE_1_2_LEV, 3 | (7 << 4));
-       if (!ret)
-               ret = reg_write(client, RJ54N1_SCALE_4_LEV, 0xf);
-
-       /* Switch to fixed resize mode */
-       if (!ret)
-               ret = reg_write(client, RJ54N1_RESIZE_CONTROL,
-                               RESIZE_HOLD_SEL | 1);
-
-       /* Set gain */
-       if (!ret)
-               ret = reg_write(client, RJ54N1_Y_GAIN, 0x84);
-
-       /*
-        * Mirror the image back: default is upside down and left-to-right...
-        * Set manual preview / still shot switching
-        */
-       if (!ret)
-               ret = reg_write(client, RJ54N1_MIRROR_STILL_MODE, 0x27);
-
-       if (!ret)
-               ret = reg_write_multiple(client, bank_4, ARRAY_SIZE(bank_4));
-
-       /* Auto exposure area */
-       if (!ret)
-               ret = reg_write(client, RJ54N1_EXPOSURE_CONTROL, 0x80);
-       /* Check current auto WB config */
-       if (!ret)
-               ret = reg_read(client, RJ54N1_WB_SEL_WEIGHT_I);
-       if (ret >= 0) {
-               rj54n1->auto_wb = ret & 0x80;
-               ret = reg_write_multiple(client, bank_5, ARRAY_SIZE(bank_5));
-       }
-       if (!ret)
-               ret = reg_write_multiple(client, bank_8, ARRAY_SIZE(bank_8));
-
-       if (!ret)
-               ret = reg_write(client, RJ54N1_RESET_STANDBY,
-                               E_EXCLK | DSP_RSTX | SEN_RSTX);
-
-       /* Commit init */
-       if (!ret)
-               ret = rj54n1_commit(client);
-
-       /* Take DSP, TG, sensor out of reset */
-       if (!ret)
-               ret = reg_write(client, RJ54N1_RESET_STANDBY,
-                               E_EXCLK | DSP_RSTX | TG_RSTX | SEN_RSTX);
-
-       /* Start register update? Same register as 0x?FE in many bank_* sets */
-       if (!ret)
-               ret = reg_write(client, RJ54N1_FWFLG, 2);
-
-       /* Constant taken from manufacturer's example */
-       msleep(700);
-
-       return ret;
-}
-
-static int rj54n1_set_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_format *format)
-{
-       struct v4l2_mbus_framefmt *mf = &format->format;
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct rj54n1 *rj54n1 = to_rj54n1(client);
-       const struct rj54n1_datafmt *fmt;
-       int output_w, output_h, max_w, max_h,
-               input_w = rj54n1->rect.width, input_h = rj54n1->rect.height;
-       int align = mf->code == MEDIA_BUS_FMT_SBGGR10_1X10 ||
-               mf->code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE ||
-               mf->code == MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE ||
-               mf->code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE ||
-               mf->code == MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE;
-       int ret;
-
-       if (format->pad)
-               return -EINVAL;
-
-       dev_dbg(&client->dev, "%s: code = %d, width = %u, height = %u\n",
-               __func__, mf->code, mf->width, mf->height);
-
-       fmt = rj54n1_find_datafmt(mf->code, rj54n1_colour_fmts,
-                                 ARRAY_SIZE(rj54n1_colour_fmts));
-       if (!fmt) {
-               fmt = rj54n1->fmt;
-               mf->code = fmt->code;
-       }
-
-       mf->field       = V4L2_FIELD_NONE;
-       mf->colorspace  = fmt->colorspace;
-
-       v4l_bound_align_image(&mf->width, 112, RJ54N1_MAX_WIDTH, align,
-                             &mf->height, 84, RJ54N1_MAX_HEIGHT, align, 0);
-
-       if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
-               cfg->try_fmt = *mf;
-               return 0;
-       }
-
-       /*
-        * Verify if the sensor has just been powered on. TODO: replace this
-        * with proper PM, when a suitable API is available.
-        */
-       ret = reg_read(client, RJ54N1_RESET_STANDBY);
-       if (ret < 0)
-               return ret;
-
-       if (!(ret & E_EXCLK)) {
-               ret = rj54n1_reg_init(client);
-               if (ret < 0)
-                       return ret;
-       }
-
-       /* RA_SEL_UL is only relevant for raw modes, ignored otherwise. */
-       switch (mf->code) {
-       case MEDIA_BUS_FMT_YUYV8_2X8:
-               ret = reg_write(client, RJ54N1_OUT_SEL, 0);
-               if (!ret)
-                       ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8);
-               break;
-       case MEDIA_BUS_FMT_YVYU8_2X8:
-               ret = reg_write(client, RJ54N1_OUT_SEL, 0);
-               if (!ret)
-                       ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8);
-               break;
-       case MEDIA_BUS_FMT_RGB565_2X8_LE:
-               ret = reg_write(client, RJ54N1_OUT_SEL, 0x11);
-               if (!ret)
-                       ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8);
-               break;
-       case MEDIA_BUS_FMT_RGB565_2X8_BE:
-               ret = reg_write(client, RJ54N1_OUT_SEL, 0x11);
-               if (!ret)
-                       ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8);
-               break;
-       case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE:
-               ret = reg_write(client, RJ54N1_OUT_SEL, 4);
-               if (!ret)
-                       ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8);
-               if (!ret)
-                       ret = reg_write(client, RJ54N1_RA_SEL_UL, 0);
-               break;
-       case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE:
-               ret = reg_write(client, RJ54N1_OUT_SEL, 4);
-               if (!ret)
-                       ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8);
-               if (!ret)
-                       ret = reg_write(client, RJ54N1_RA_SEL_UL, 8);
-               break;
-       case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE:
-               ret = reg_write(client, RJ54N1_OUT_SEL, 4);
-               if (!ret)
-                       ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8);
-               if (!ret)
-                       ret = reg_write(client, RJ54N1_RA_SEL_UL, 0);
-               break;
-       case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE:
-               ret = reg_write(client, RJ54N1_OUT_SEL, 4);
-               if (!ret)
-                       ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8);
-               if (!ret)
-                       ret = reg_write(client, RJ54N1_RA_SEL_UL, 8);
-               break;
-       case MEDIA_BUS_FMT_SBGGR10_1X10:
-               ret = reg_write(client, RJ54N1_OUT_SEL, 5);
-               break;
-       default:
-               ret = -EINVAL;
-       }
-
-       /* Special case: a raw mode with 10 bits of data per clock tick */
-       if (!ret)
-               ret = reg_set(client, RJ54N1_OCLK_SEL_EN,
-                             (mf->code == MEDIA_BUS_FMT_SBGGR10_1X10) << 1, 2);
-
-       if (ret < 0)
-               return ret;
-
-       /* Supported scales 1:1 >= scale > 1:16 */
-       max_w = mf->width * (16 * 1024 - 1) / 1024;
-       if (input_w > max_w)
-               input_w = max_w;
-       max_h = mf->height * (16 * 1024 - 1) / 1024;
-       if (input_h > max_h)
-               input_h = max_h;
-
-       output_w = mf->width;
-       output_h = mf->height;
-
-       ret = rj54n1_sensor_scale(sd, &input_w, &input_h, &output_w, &output_h);
-       if (ret < 0)
-               return ret;
-
-       fmt = rj54n1_find_datafmt(mf->code, rj54n1_colour_fmts,
-                                 ARRAY_SIZE(rj54n1_colour_fmts));
-
-       rj54n1->fmt             = fmt;
-       rj54n1->resize          = ret;
-       rj54n1->rect.width      = input_w;
-       rj54n1->rect.height     = input_h;
-       rj54n1->width           = output_w;
-       rj54n1->height          = output_h;
-
-       mf->width               = output_w;
-       mf->height              = output_h;
-       mf->field               = V4L2_FIELD_NONE;
-       mf->colorspace          = fmt->colorspace;
-
-       return 0;
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int rj54n1_g_register(struct v4l2_subdev *sd,
-                            struct v4l2_dbg_register *reg)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (reg->reg < 0x400 || reg->reg > 0x1fff)
-               /* Registers > 0x0800 are only available from Sharp support */
-               return -EINVAL;
-
-       reg->size = 1;
-       reg->val = reg_read(client, reg->reg);
-
-       if (reg->val > 0xff)
-               return -EIO;
-
-       return 0;
-}
-
-static int rj54n1_s_register(struct v4l2_subdev *sd,
-                            const struct v4l2_dbg_register *reg)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (reg->reg < 0x400 || reg->reg > 0x1fff)
-               /* Registers >= 0x0800 are only available from Sharp support */
-               return -EINVAL;
-
-       if (reg_write(client, reg->reg, reg->val) < 0)
-               return -EIO;
-
-       return 0;
-}
-#endif
-
-static int rj54n1_s_power(struct v4l2_subdev *sd, int on)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
-       struct rj54n1 *rj54n1 = to_rj54n1(client);
-
-       return soc_camera_set_power(&client->dev, ssdd, rj54n1->clk, on);
-}
-
-static int rj54n1_s_ctrl(struct v4l2_ctrl *ctrl)
-{
-       struct rj54n1 *rj54n1 = container_of(ctrl->handler, struct rj54n1, hdl);
-       struct v4l2_subdev *sd = &rj54n1->subdev;
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int data;
-
-       switch (ctrl->id) {
-       case V4L2_CID_VFLIP:
-               if (ctrl->val)
-                       data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 0, 1);
-               else
-                       data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 1, 1);
-               if (data < 0)
-                       return -EIO;
-               return 0;
-       case V4L2_CID_HFLIP:
-               if (ctrl->val)
-                       data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 0, 2);
-               else
-                       data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 2, 2);
-               if (data < 0)
-                       return -EIO;
-               return 0;
-       case V4L2_CID_GAIN:
-               if (reg_write(client, RJ54N1_Y_GAIN, ctrl->val * 2) < 0)
-                       return -EIO;
-               return 0;
-       case V4L2_CID_AUTO_WHITE_BALANCE:
-               /* Auto WB area - whole image */
-               if (reg_set(client, RJ54N1_WB_SEL_WEIGHT_I, ctrl->val << 7,
-                           0x80) < 0)
-                       return -EIO;
-               rj54n1->auto_wb = ctrl->val;
-               return 0;
-       }
-
-       return -EINVAL;
-}
-
-static const struct v4l2_ctrl_ops rj54n1_ctrl_ops = {
-       .s_ctrl = rj54n1_s_ctrl,
-};
-
-static const struct v4l2_subdev_core_ops rj54n1_subdev_core_ops = {
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       .g_register     = rj54n1_g_register,
-       .s_register     = rj54n1_s_register,
-#endif
-       .s_power        = rj54n1_s_power,
-};
-
-static int rj54n1_g_mbus_config(struct v4l2_subdev *sd,
-                               struct v4l2_mbus_config *cfg)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
-
-       cfg->flags =
-               V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING |
-               V4L2_MBUS_MASTER | V4L2_MBUS_DATA_ACTIVE_HIGH |
-               V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH;
-       cfg->type = V4L2_MBUS_PARALLEL;
-       cfg->flags = soc_camera_apply_board_flags(ssdd, cfg);
-
-       return 0;
-}
-
-static int rj54n1_s_mbus_config(struct v4l2_subdev *sd,
-                               const struct v4l2_mbus_config *cfg)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
-
-       /* Figures 2.5-1 to 2.5-3 - default falling pixclk edge */
-       if (soc_camera_apply_board_flags(ssdd, cfg) &
-           V4L2_MBUS_PCLK_SAMPLE_RISING)
-               return reg_write(client, RJ54N1_OUT_SIGPO, 1 << 4);
-       else
-               return reg_write(client, RJ54N1_OUT_SIGPO, 0);
-}
-
-static const struct v4l2_subdev_video_ops rj54n1_subdev_video_ops = {
-       .s_stream       = rj54n1_s_stream,
-       .g_mbus_config  = rj54n1_g_mbus_config,
-       .s_mbus_config  = rj54n1_s_mbus_config,
-};
-
-static const struct v4l2_subdev_pad_ops rj54n1_subdev_pad_ops = {
-       .enum_mbus_code = rj54n1_enum_mbus_code,
-       .get_selection  = rj54n1_get_selection,
-       .set_selection  = rj54n1_set_selection,
-       .get_fmt        = rj54n1_get_fmt,
-       .set_fmt        = rj54n1_set_fmt,
-};
-
-static const struct v4l2_subdev_ops rj54n1_subdev_ops = {
-       .core   = &rj54n1_subdev_core_ops,
-       .video  = &rj54n1_subdev_video_ops,
-       .pad    = &rj54n1_subdev_pad_ops,
-};
-
-/*
- * Interface active, can use i2c. If it fails, it can indeed mean, that
- * this wasn't our capture interface, so, we wait for the right one
- */
-static int rj54n1_video_probe(struct i2c_client *client,
-                             struct rj54n1_pdata *priv)
-{
-       struct rj54n1 *rj54n1 = to_rj54n1(client);
-       int data1, data2;
-       int ret;
-
-       ret = rj54n1_s_power(&rj54n1->subdev, 1);
-       if (ret < 0)
-               return ret;
-
-       /* Read out the chip version register */
-       data1 = reg_read(client, RJ54N1_DEV_CODE);
-       data2 = reg_read(client, RJ54N1_DEV_CODE2);
-
-       if (data1 != 0x51 || data2 != 0x10) {
-               ret = -ENODEV;
-               dev_info(&client->dev, "No RJ54N1CB0C found, read 0x%x:0x%x\n",
-                        data1, data2);
-               goto done;
-       }
-
-       /* Configure IOCTL polarity from the platform data: 0 or 1 << 7. */
-       ret = reg_write(client, RJ54N1_IOC, priv->ioctl_high << 7);
-       if (ret < 0)
-               goto done;
-
-       dev_info(&client->dev, "Detected a RJ54N1CB0C chip ID 0x%x:0x%x\n",
-                data1, data2);
-
-       ret = v4l2_ctrl_handler_setup(&rj54n1->hdl);
-
-done:
-       rj54n1_s_power(&rj54n1->subdev, 0);
-       return ret;
-}
-
-static int rj54n1_probe(struct i2c_client *client,
-                       const struct i2c_device_id *did)
-{
-       struct rj54n1 *rj54n1;
-       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
-       struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
-       struct rj54n1_pdata *rj54n1_priv;
-       int ret;
-
-       if (!ssdd || !ssdd->drv_priv) {
-               dev_err(&client->dev, "RJ54N1CB0C: missing platform data!\n");
-               return -EINVAL;
-       }
-
-       rj54n1_priv = ssdd->drv_priv;
-
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
-               dev_warn(&adapter->dev,
-                        "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE\n");
-               return -EIO;
-       }
-
-       rj54n1 = devm_kzalloc(&client->dev, sizeof(struct rj54n1), GFP_KERNEL);
-       if (!rj54n1)
-               return -ENOMEM;
-
-       v4l2_i2c_subdev_init(&rj54n1->subdev, client, &rj54n1_subdev_ops);
-       v4l2_ctrl_handler_init(&rj54n1->hdl, 4);
-       v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops,
-                       V4L2_CID_VFLIP, 0, 1, 1, 0);
-       v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops,
-                       V4L2_CID_HFLIP, 0, 1, 1, 0);
-       v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops,
-                       V4L2_CID_GAIN, 0, 127, 1, 66);
-       v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops,
-                       V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
-       rj54n1->subdev.ctrl_handler = &rj54n1->hdl;
-       if (rj54n1->hdl.error)
-               return rj54n1->hdl.error;
-
-       rj54n1->clk_div         = clk_div;
-       rj54n1->rect.left       = RJ54N1_COLUMN_SKIP;
-       rj54n1->rect.top        = RJ54N1_ROW_SKIP;
-       rj54n1->rect.width      = RJ54N1_MAX_WIDTH;
-       rj54n1->rect.height     = RJ54N1_MAX_HEIGHT;
-       rj54n1->width           = RJ54N1_MAX_WIDTH;
-       rj54n1->height          = RJ54N1_MAX_HEIGHT;
-       rj54n1->fmt             = &rj54n1_colour_fmts[0];
-       rj54n1->resize          = 1024;
-       rj54n1->tgclk_mhz       = (rj54n1_priv->mclk_freq / PLL_L * PLL_N) /
-               (clk_div.ratio_tg + 1) / (clk_div.ratio_t + 1);
-
-       rj54n1->clk = v4l2_clk_get(&client->dev, "mclk");
-       if (IS_ERR(rj54n1->clk)) {
-               ret = PTR_ERR(rj54n1->clk);
-               goto eclkget;
-       }
-
-       ret = rj54n1_video_probe(client, rj54n1_priv);
-       if (ret < 0) {
-               v4l2_clk_put(rj54n1->clk);
-eclkget:
-               v4l2_ctrl_handler_free(&rj54n1->hdl);
-       }
-
-       return ret;
-}
-
-static int rj54n1_remove(struct i2c_client *client)
-{
-       struct rj54n1 *rj54n1 = to_rj54n1(client);
-       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
-
-       v4l2_clk_put(rj54n1->clk);
-       v4l2_device_unregister_subdev(&rj54n1->subdev);
-       if (ssdd->free_bus)
-               ssdd->free_bus(ssdd);
-       v4l2_ctrl_handler_free(&rj54n1->hdl);
-
-       return 0;
-}
-
-static const struct i2c_device_id rj54n1_id[] = {
-       { "rj54n1cb0c", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, rj54n1_id);
-
-static struct i2c_driver rj54n1_i2c_driver = {
-       .driver = {
-               .name = "rj54n1cb0c",
-       },
-       .probe          = rj54n1_probe,
-       .remove         = rj54n1_remove,
-       .id_table       = rj54n1_id,
-};
-
-module_i2c_driver(rj54n1_i2c_driver);
-
-MODULE_DESCRIPTION("Sharp RJ54N1CB0C Camera driver");
-MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/soc_camera/soc_mt9m001.c b/drivers/media/i2c/soc_camera/soc_mt9m001.c
new file mode 100644 (file)
index 0000000..a1a85ff
--- /dev/null
@@ -0,0 +1,757 @@
+/*
+ * Driver for MT9M001 CMOS Image Sensor from Micron
+ *
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * 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.
+ */
+
+#include <linux/videodev2.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/log2.h>
+#include <linux/module.h>
+
+#include <media/soc_camera.h>
+#include <media/drv-intf/soc_mediabus.h>
+#include <media/v4l2-clk.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-ctrls.h>
+
+/*
+ * mt9m001 i2c address 0x5d
+ * The platform has to define struct i2c_board_info objects and link to them
+ * from struct soc_camera_host_desc
+ */
+
+/* mt9m001 selected register addresses */
+#define MT9M001_CHIP_VERSION           0x00
+#define MT9M001_ROW_START              0x01
+#define MT9M001_COLUMN_START           0x02
+#define MT9M001_WINDOW_HEIGHT          0x03
+#define MT9M001_WINDOW_WIDTH           0x04
+#define MT9M001_HORIZONTAL_BLANKING    0x05
+#define MT9M001_VERTICAL_BLANKING      0x06
+#define MT9M001_OUTPUT_CONTROL         0x07
+#define MT9M001_SHUTTER_WIDTH          0x09
+#define MT9M001_FRAME_RESTART          0x0b
+#define MT9M001_SHUTTER_DELAY          0x0c
+#define MT9M001_RESET                  0x0d
+#define MT9M001_READ_OPTIONS1          0x1e
+#define MT9M001_READ_OPTIONS2          0x20
+#define MT9M001_GLOBAL_GAIN            0x35
+#define MT9M001_CHIP_ENABLE            0xF1
+
+#define MT9M001_MAX_WIDTH              1280
+#define MT9M001_MAX_HEIGHT             1024
+#define MT9M001_MIN_WIDTH              48
+#define MT9M001_MIN_HEIGHT             32
+#define MT9M001_COLUMN_SKIP            20
+#define MT9M001_ROW_SKIP               12
+
+/* MT9M001 has only one fixed colorspace per pixelcode */
+struct mt9m001_datafmt {
+       u32     code;
+       enum v4l2_colorspace            colorspace;
+};
+
+/* Find a data format by a pixel code in an array */
+static const struct mt9m001_datafmt *mt9m001_find_datafmt(
+       u32 code, const struct mt9m001_datafmt *fmt,
+       int n)
+{
+       int i;
+       for (i = 0; i < n; i++)
+               if (fmt[i].code == code)
+                       return fmt + i;
+
+       return NULL;
+}
+
+static const struct mt9m001_datafmt mt9m001_colour_fmts[] = {
+       /*
+        * Order important: first natively supported,
+        * second supported with a GPIO extender
+        */
+       {MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB},
+       {MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
+};
+
+static const struct mt9m001_datafmt mt9m001_monochrome_fmts[] = {
+       /* Order important - see above */
+       {MEDIA_BUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG},
+       {MEDIA_BUS_FMT_Y8_1X8, V4L2_COLORSPACE_JPEG},
+};
+
+struct mt9m001 {
+       struct v4l2_subdev subdev;
+       struct v4l2_ctrl_handler hdl;
+       struct {
+               /* exposure/auto-exposure cluster */
+               struct v4l2_ctrl *autoexposure;
+               struct v4l2_ctrl *exposure;
+       };
+       struct v4l2_rect rect;  /* Sensor window */
+       struct v4l2_clk *clk;
+       const struct mt9m001_datafmt *fmt;
+       const struct mt9m001_datafmt *fmts;
+       int num_fmts;
+       unsigned int total_h;
+       unsigned short y_skip_top;      /* Lines to skip at the top */
+};
+
+static struct mt9m001 *to_mt9m001(const struct i2c_client *client)
+{
+       return container_of(i2c_get_clientdata(client), struct mt9m001, subdev);
+}
+
+static int reg_read(struct i2c_client *client, const u8 reg)
+{
+       return i2c_smbus_read_word_swapped(client, reg);
+}
+
+static int reg_write(struct i2c_client *client, const u8 reg,
+                    const u16 data)
+{
+       return i2c_smbus_write_word_swapped(client, reg, data);
+}
+
+static int reg_set(struct i2c_client *client, const u8 reg,
+                  const u16 data)
+{
+       int ret;
+
+       ret = reg_read(client, reg);
+       if (ret < 0)
+               return ret;
+       return reg_write(client, reg, ret | data);
+}
+
+static int reg_clear(struct i2c_client *client, const u8 reg,
+                    const u16 data)
+{
+       int ret;
+
+       ret = reg_read(client, reg);
+       if (ret < 0)
+               return ret;
+       return reg_write(client, reg, ret & ~data);
+}
+
+static int mt9m001_init(struct i2c_client *client)
+{
+       int ret;
+
+       dev_dbg(&client->dev, "%s\n", __func__);
+
+       /*
+        * We don't know, whether platform provides reset, issue a soft reset
+        * too. This returns all registers to their default values.
+        */
+       ret = reg_write(client, MT9M001_RESET, 1);
+       if (!ret)
+               ret = reg_write(client, MT9M001_RESET, 0);
+
+       /* Disable chip, synchronous option update */
+       if (!ret)
+               ret = reg_write(client, MT9M001_OUTPUT_CONTROL, 0);
+
+       return ret;
+}
+
+static int mt9m001_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       /* Switch to master "normal" mode or stop sensor readout */
+       if (reg_write(client, MT9M001_OUTPUT_CONTROL, enable ? 2 : 0) < 0)
+               return -EIO;
+       return 0;
+}
+
+static int mt9m001_set_selection(struct v4l2_subdev *sd,
+               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_selection *sel)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct mt9m001 *mt9m001 = to_mt9m001(client);
+       struct v4l2_rect rect = sel->r;
+       const u16 hblank = 9, vblank = 25;
+       int ret;
+
+       if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
+           sel->target != V4L2_SEL_TGT_CROP)
+               return -EINVAL;
+
+       if (mt9m001->fmts == mt9m001_colour_fmts)
+               /*
+                * Bayer format - even number of rows for simplicity,
+                * but let the user play with the top row.
+                */
+               rect.height = ALIGN(rect.height, 2);
+
+       /* Datasheet requirement: see register description */
+       rect.width = ALIGN(rect.width, 2);
+       rect.left = ALIGN(rect.left, 2);
+
+       soc_camera_limit_side(&rect.left, &rect.width,
+                    MT9M001_COLUMN_SKIP, MT9M001_MIN_WIDTH, MT9M001_MAX_WIDTH);
+
+       soc_camera_limit_side(&rect.top, &rect.height,
+                    MT9M001_ROW_SKIP, MT9M001_MIN_HEIGHT, MT9M001_MAX_HEIGHT);
+
+       mt9m001->total_h = rect.height + mt9m001->y_skip_top + vblank;
+
+       /* Blanking and start values - default... */
+       ret = reg_write(client, MT9M001_HORIZONTAL_BLANKING, hblank);
+       if (!ret)
+               ret = reg_write(client, MT9M001_VERTICAL_BLANKING, vblank);
+
+       /*
+        * The caller provides a supported format, as verified per
+        * call to .set_fmt(FORMAT_TRY).
+        */
+       if (!ret)
+               ret = reg_write(client, MT9M001_COLUMN_START, rect.left);
+       if (!ret)
+               ret = reg_write(client, MT9M001_ROW_START, rect.top);
+       if (!ret)
+               ret = reg_write(client, MT9M001_WINDOW_WIDTH, rect.width - 1);
+       if (!ret)
+               ret = reg_write(client, MT9M001_WINDOW_HEIGHT,
+                               rect.height + mt9m001->y_skip_top - 1);
+       if (!ret && v4l2_ctrl_g_ctrl(mt9m001->autoexposure) == V4L2_EXPOSURE_AUTO)
+               ret = reg_write(client, MT9M001_SHUTTER_WIDTH, mt9m001->total_h);
+
+       if (!ret)
+               mt9m001->rect = rect;
+
+       return ret;
+}
+
+static int mt9m001_get_selection(struct v4l2_subdev *sd,
+               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_selection *sel)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct mt9m001 *mt9m001 = to_mt9m001(client);
+
+       if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+               return -EINVAL;
+
+       switch (sel->target) {
+       case V4L2_SEL_TGT_CROP_BOUNDS:
+               sel->r.left = MT9M001_COLUMN_SKIP;
+               sel->r.top = MT9M001_ROW_SKIP;
+               sel->r.width = MT9M001_MAX_WIDTH;
+               sel->r.height = MT9M001_MAX_HEIGHT;
+               return 0;
+       case V4L2_SEL_TGT_CROP:
+               sel->r = mt9m001->rect;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int mt9m001_get_fmt(struct v4l2_subdev *sd,
+               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_format *format)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct mt9m001 *mt9m001 = to_mt9m001(client);
+       struct v4l2_mbus_framefmt *mf = &format->format;
+
+       if (format->pad)
+               return -EINVAL;
+
+       mf->width       = mt9m001->rect.width;
+       mf->height      = mt9m001->rect.height;
+       mf->code        = mt9m001->fmt->code;
+       mf->colorspace  = mt9m001->fmt->colorspace;
+       mf->field       = V4L2_FIELD_NONE;
+
+       return 0;
+}
+
+static int mt9m001_s_fmt(struct v4l2_subdev *sd,
+                        const struct mt9m001_datafmt *fmt,
+                        struct v4l2_mbus_framefmt *mf)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct mt9m001 *mt9m001 = to_mt9m001(client);
+       struct v4l2_subdev_selection sel = {
+               .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+               .target = V4L2_SEL_TGT_CROP,
+               .r.left = mt9m001->rect.left,
+               .r.top = mt9m001->rect.top,
+               .r.width = mf->width,
+               .r.height = mf->height,
+       };
+       int ret;
+
+       /* No support for scaling so far, just crop. TODO: use skipping */
+       ret = mt9m001_set_selection(sd, NULL, &sel);
+       if (!ret) {
+               mf->width       = mt9m001->rect.width;
+               mf->height      = mt9m001->rect.height;
+               mt9m001->fmt    = fmt;
+               mf->colorspace  = fmt->colorspace;
+       }
+
+       return ret;
+}
+
+static int mt9m001_set_fmt(struct v4l2_subdev *sd,
+               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_format *format)
+{
+       struct v4l2_mbus_framefmt *mf = &format->format;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct mt9m001 *mt9m001 = to_mt9m001(client);
+       const struct mt9m001_datafmt *fmt;
+
+       if (format->pad)
+               return -EINVAL;
+
+       v4l_bound_align_image(&mf->width, MT9M001_MIN_WIDTH,
+               MT9M001_MAX_WIDTH, 1,
+               &mf->height, MT9M001_MIN_HEIGHT + mt9m001->y_skip_top,
+               MT9M001_MAX_HEIGHT + mt9m001->y_skip_top, 0, 0);
+
+       if (mt9m001->fmts == mt9m001_colour_fmts)
+               mf->height = ALIGN(mf->height - 1, 2);
+
+       fmt = mt9m001_find_datafmt(mf->code, mt9m001->fmts,
+                                  mt9m001->num_fmts);
+       if (!fmt) {
+               fmt = mt9m001->fmt;
+               mf->code = fmt->code;
+       }
+
+       mf->colorspace  = fmt->colorspace;
+
+       if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+               return mt9m001_s_fmt(sd, fmt, mf);
+       cfg->try_fmt = *mf;
+       return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int mt9m001_g_register(struct v4l2_subdev *sd,
+                             struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (reg->reg > 0xff)
+               return -EINVAL;
+
+       reg->size = 2;
+       reg->val = reg_read(client, reg->reg);
+
+       if (reg->val > 0xffff)
+               return -EIO;
+
+       return 0;
+}
+
+static int mt9m001_s_register(struct v4l2_subdev *sd,
+                             const struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (reg->reg > 0xff)
+               return -EINVAL;
+
+       if (reg_write(client, reg->reg, reg->val) < 0)
+               return -EIO;
+
+       return 0;
+}
+#endif
+
+static int mt9m001_s_power(struct v4l2_subdev *sd, int on)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct mt9m001 *mt9m001 = to_mt9m001(client);
+
+       return soc_camera_set_power(&client->dev, ssdd, mt9m001->clk, on);
+}
+
+static int mt9m001_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct mt9m001 *mt9m001 = container_of(ctrl->handler,
+                                              struct mt9m001, hdl);
+       s32 min, max;
+
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE_AUTO:
+               min = mt9m001->exposure->minimum;
+               max = mt9m001->exposure->maximum;
+               mt9m001->exposure->val =
+                       (524 + (mt9m001->total_h - 1) * (max - min)) / 1048 + min;
+               break;
+       }
+       return 0;
+}
+
+static int mt9m001_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct mt9m001 *mt9m001 = container_of(ctrl->handler,
+                                              struct mt9m001, hdl);
+       struct v4l2_subdev *sd = &mt9m001->subdev;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct v4l2_ctrl *exp = mt9m001->exposure;
+       int data;
+
+       switch (ctrl->id) {
+       case V4L2_CID_VFLIP:
+               if (ctrl->val)
+                       data = reg_set(client, MT9M001_READ_OPTIONS2, 0x8000);
+               else
+                       data = reg_clear(client, MT9M001_READ_OPTIONS2, 0x8000);
+               if (data < 0)
+                       return -EIO;
+               return 0;
+
+       case V4L2_CID_GAIN:
+               /* See Datasheet Table 7, Gain settings. */
+               if (ctrl->val <= ctrl->default_value) {
+                       /* Pack it into 0..1 step 0.125, register values 0..8 */
+                       unsigned long range = ctrl->default_value - ctrl->minimum;
+                       data = ((ctrl->val - (s32)ctrl->minimum) * 8 + range / 2) / range;
+
+                       dev_dbg(&client->dev, "Setting gain %d\n", data);
+                       data = reg_write(client, MT9M001_GLOBAL_GAIN, data);
+                       if (data < 0)
+                               return -EIO;
+               } else {
+                       /* Pack it into 1.125..15 variable step, register values 9..67 */
+                       /* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */
+                       unsigned long range = ctrl->maximum - ctrl->default_value - 1;
+                       unsigned long gain = ((ctrl->val - (s32)ctrl->default_value - 1) *
+                                              111 + range / 2) / range + 9;
+
+                       if (gain <= 32)
+                               data = gain;
+                       else if (gain <= 64)
+                               data = ((gain - 32) * 16 + 16) / 32 + 80;
+                       else
+                               data = ((gain - 64) * 7 + 28) / 56 + 96;
+
+                       dev_dbg(&client->dev, "Setting gain from %d to %d\n",
+                                reg_read(client, MT9M001_GLOBAL_GAIN), data);
+                       data = reg_write(client, MT9M001_GLOBAL_GAIN, data);
+                       if (data < 0)
+                               return -EIO;
+               }
+               return 0;
+
+       case V4L2_CID_EXPOSURE_AUTO:
+               if (ctrl->val == V4L2_EXPOSURE_MANUAL) {
+                       unsigned long range = exp->maximum - exp->minimum;
+                       unsigned long shutter = ((exp->val - (s32)exp->minimum) * 1048 +
+                                                range / 2) / range + 1;
+
+                       dev_dbg(&client->dev,
+                               "Setting shutter width from %d to %lu\n",
+                               reg_read(client, MT9M001_SHUTTER_WIDTH), shutter);
+                       if (reg_write(client, MT9M001_SHUTTER_WIDTH, shutter) < 0)
+                               return -EIO;
+               } else {
+                       const u16 vblank = 25;
+
+                       mt9m001->total_h = mt9m001->rect.height +
+                               mt9m001->y_skip_top + vblank;
+                       if (reg_write(client, MT9M001_SHUTTER_WIDTH, mt9m001->total_h) < 0)
+                               return -EIO;
+               }
+               return 0;
+       }
+       return -EINVAL;
+}
+
+/*
+ * Interface active, can use i2c. If it fails, it can indeed mean, that
+ * this wasn't our capture interface, so, we wait for the right one
+ */
+static int mt9m001_video_probe(struct soc_camera_subdev_desc *ssdd,
+                              struct i2c_client *client)
+{
+       struct mt9m001 *mt9m001 = to_mt9m001(client);
+       s32 data;
+       unsigned long flags;
+       int ret;
+
+       ret = mt9m001_s_power(&mt9m001->subdev, 1);
+       if (ret < 0)
+               return ret;
+
+       /* Enable the chip */
+       data = reg_write(client, MT9M001_CHIP_ENABLE, 1);
+       dev_dbg(&client->dev, "write: %d\n", data);
+
+       /* Read out the chip version register */
+       data = reg_read(client, MT9M001_CHIP_VERSION);
+
+       /* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */
+       switch (data) {
+       case 0x8411:
+       case 0x8421:
+               mt9m001->fmts = mt9m001_colour_fmts;
+               break;
+       case 0x8431:
+               mt9m001->fmts = mt9m001_monochrome_fmts;
+               break;
+       default:
+               dev_err(&client->dev,
+                       "No MT9M001 chip detected, register read %x\n", data);
+               ret = -ENODEV;
+               goto done;
+       }
+
+       mt9m001->num_fmts = 0;
+
+       /*
+        * This is a 10bit sensor, so by default we only allow 10bit.
+        * The platform may support different bus widths due to
+        * different routing of the data lines.
+        */
+       if (ssdd->query_bus_param)
+               flags = ssdd->query_bus_param(ssdd);
+       else
+               flags = SOCAM_DATAWIDTH_10;
+
+       if (flags & SOCAM_DATAWIDTH_10)
+               mt9m001->num_fmts++;
+       else
+               mt9m001->fmts++;
+
+       if (flags & SOCAM_DATAWIDTH_8)
+               mt9m001->num_fmts++;
+
+       mt9m001->fmt = &mt9m001->fmts[0];
+
+       dev_info(&client->dev, "Detected a MT9M001 chip ID %x (%s)\n", data,
+                data == 0x8431 ? "C12STM" : "C12ST");
+
+       ret = mt9m001_init(client);
+       if (ret < 0) {
+               dev_err(&client->dev, "Failed to initialise the camera\n");
+               goto done;
+       }
+
+       /* mt9m001_init() has reset the chip, returning registers to defaults */
+       ret = v4l2_ctrl_handler_setup(&mt9m001->hdl);
+
+done:
+       mt9m001_s_power(&mt9m001->subdev, 0);
+       return ret;
+}
+
+static void mt9m001_video_remove(struct soc_camera_subdev_desc *ssdd)
+{
+       if (ssdd->free_bus)
+               ssdd->free_bus(ssdd);
+}
+
+static int mt9m001_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct mt9m001 *mt9m001 = to_mt9m001(client);
+
+       *lines = mt9m001->y_skip_top;
+
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops mt9m001_ctrl_ops = {
+       .g_volatile_ctrl = mt9m001_g_volatile_ctrl,
+       .s_ctrl = mt9m001_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = {
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .g_register     = mt9m001_g_register,
+       .s_register     = mt9m001_s_register,
+#endif
+       .s_power        = mt9m001_s_power,
+};
+
+static int mt9m001_enum_mbus_code(struct v4l2_subdev *sd,
+               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_mbus_code_enum *code)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct mt9m001 *mt9m001 = to_mt9m001(client);
+
+       if (code->pad || code->index >= mt9m001->num_fmts)
+               return -EINVAL;
+
+       code->code = mt9m001->fmts[code->index].code;
+       return 0;
+}
+
+static int mt9m001_g_mbus_config(struct v4l2_subdev *sd,
+                               struct v4l2_mbus_config *cfg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+
+       /* MT9M001 has all capture_format parameters fixed */
+       cfg->flags = V4L2_MBUS_PCLK_SAMPLE_FALLING |
+               V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH |
+               V4L2_MBUS_DATA_ACTIVE_HIGH | V4L2_MBUS_MASTER;
+       cfg->type = V4L2_MBUS_PARALLEL;
+       cfg->flags = soc_camera_apply_board_flags(ssdd, cfg);
+
+       return 0;
+}
+
+static int mt9m001_s_mbus_config(struct v4l2_subdev *sd,
+                               const struct v4l2_mbus_config *cfg)
+{
+       const struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct mt9m001 *mt9m001 = to_mt9m001(client);
+       unsigned int bps = soc_mbus_get_fmtdesc(mt9m001->fmt->code)->bits_per_sample;
+
+       if (ssdd->set_bus_param)
+               return ssdd->set_bus_param(ssdd, 1 << (bps - 1));
+
+       /*
+        * Without board specific bus width settings we only support the
+        * sensors native bus width
+        */
+       return bps == 10 ? 0 : -EINVAL;
+}
+
+static const struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = {
+       .s_stream       = mt9m001_s_stream,
+       .g_mbus_config  = mt9m001_g_mbus_config,
+       .s_mbus_config  = mt9m001_s_mbus_config,
+};
+
+static const struct v4l2_subdev_sensor_ops mt9m001_subdev_sensor_ops = {
+       .g_skip_top_lines       = mt9m001_g_skip_top_lines,
+};
+
+static const struct v4l2_subdev_pad_ops mt9m001_subdev_pad_ops = {
+       .enum_mbus_code = mt9m001_enum_mbus_code,
+       .get_selection  = mt9m001_get_selection,
+       .set_selection  = mt9m001_set_selection,
+       .get_fmt        = mt9m001_get_fmt,
+       .set_fmt        = mt9m001_set_fmt,
+};
+
+static const struct v4l2_subdev_ops mt9m001_subdev_ops = {
+       .core   = &mt9m001_subdev_core_ops,
+       .video  = &mt9m001_subdev_video_ops,
+       .sensor = &mt9m001_subdev_sensor_ops,
+       .pad    = &mt9m001_subdev_pad_ops,
+};
+
+static int mt9m001_probe(struct i2c_client *client,
+                        const struct i2c_device_id *did)
+{
+       struct mt9m001 *mt9m001;
+       struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       int ret;
+
+       if (!ssdd) {
+               dev_err(&client->dev, "MT9M001 driver needs platform data\n");
+               return -EINVAL;
+       }
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
+               dev_warn(&adapter->dev,
+                        "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
+               return -EIO;
+       }
+
+       mt9m001 = devm_kzalloc(&client->dev, sizeof(struct mt9m001), GFP_KERNEL);
+       if (!mt9m001)
+               return -ENOMEM;
+
+       v4l2_i2c_subdev_init(&mt9m001->subdev, client, &mt9m001_subdev_ops);
+       v4l2_ctrl_handler_init(&mt9m001->hdl, 4);
+       v4l2_ctrl_new_std(&mt9m001->hdl, &mt9m001_ctrl_ops,
+                       V4L2_CID_VFLIP, 0, 1, 1, 0);
+       v4l2_ctrl_new_std(&mt9m001->hdl, &mt9m001_ctrl_ops,
+                       V4L2_CID_GAIN, 0, 127, 1, 64);
+       mt9m001->exposure = v4l2_ctrl_new_std(&mt9m001->hdl, &mt9m001_ctrl_ops,
+                       V4L2_CID_EXPOSURE, 1, 255, 1, 255);
+       /*
+        * Simulated autoexposure. If enabled, we calculate shutter width
+        * ourselves in the driver based on vertical blanking and frame width
+        */
+       mt9m001->autoexposure = v4l2_ctrl_new_std_menu(&mt9m001->hdl,
+                       &mt9m001_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0,
+                       V4L2_EXPOSURE_AUTO);
+       mt9m001->subdev.ctrl_handler = &mt9m001->hdl;
+       if (mt9m001->hdl.error)
+               return mt9m001->hdl.error;
+
+       v4l2_ctrl_auto_cluster(2, &mt9m001->autoexposure,
+                                       V4L2_EXPOSURE_MANUAL, true);
+
+       /* Second stage probe - when a capture adapter is there */
+       mt9m001->y_skip_top     = 0;
+       mt9m001->rect.left      = MT9M001_COLUMN_SKIP;
+       mt9m001->rect.top       = MT9M001_ROW_SKIP;
+       mt9m001->rect.width     = MT9M001_MAX_WIDTH;
+       mt9m001->rect.height    = MT9M001_MAX_HEIGHT;
+
+       mt9m001->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(mt9m001->clk)) {
+               ret = PTR_ERR(mt9m001->clk);
+               goto eclkget;
+       }
+
+       ret = mt9m001_video_probe(ssdd, client);
+       if (ret) {
+               v4l2_clk_put(mt9m001->clk);
+eclkget:
+               v4l2_ctrl_handler_free(&mt9m001->hdl);
+       }
+
+       return ret;
+}
+
+static int mt9m001_remove(struct i2c_client *client)
+{
+       struct mt9m001 *mt9m001 = to_mt9m001(client);
+       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+
+       v4l2_clk_put(mt9m001->clk);
+       v4l2_device_unregister_subdev(&mt9m001->subdev);
+       v4l2_ctrl_handler_free(&mt9m001->hdl);
+       mt9m001_video_remove(ssdd);
+
+       return 0;
+}
+
+static const struct i2c_device_id mt9m001_id[] = {
+       { "mt9m001", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, mt9m001_id);
+
+static struct i2c_driver mt9m001_i2c_driver = {
+       .driver = {
+               .name = "mt9m001",
+       },
+       .probe          = mt9m001_probe,
+       .remove         = mt9m001_remove,
+       .id_table       = mt9m001_id,
+};
+
+module_i2c_driver(mt9m001_i2c_driver);
+
+MODULE_DESCRIPTION("Micron MT9M001 Camera driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/soc_camera/soc_mt9t112.c b/drivers/media/i2c/soc_camera/soc_mt9t112.c
new file mode 100644 (file)
index 0000000..ea1ff27
--- /dev/null
@@ -0,0 +1,1157 @@
+/*
+ * mt9t112 Camera Driver
+ *
+ * Copyright (C) 2009 Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * Based on ov772x driver, mt9m111 driver,
+ *
+ * Copyright (C) 2008 Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ * Copyright (C) 2008, Robert Jarzmik <robert.jarzmik@free.fr>
+ * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
+ * Copyright (C) 2008 Magnus Damm
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/videodev2.h>
+
+#include <media/i2c/mt9t112.h>
+#include <media/soc_camera.h>
+#include <media/v4l2-clk.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-image-sizes.h>
+
+/* you can check PLL/clock info */
+/* #define EXT_CLOCK 24000000 */
+
+/************************************************************************
+                       macro
+************************************************************************/
+/*
+ * frame size
+ */
+#define MAX_WIDTH   2048
+#define MAX_HEIGHT  1536
+
+/*
+ * macro of read/write
+ */
+#define ECHECKER(ret, x)               \
+       do {                            \
+               (ret) = (x);            \
+               if ((ret) < 0)          \
+                       return (ret);   \
+       } while (0)
+
+#define mt9t112_reg_write(ret, client, a, b) \
+       ECHECKER(ret, __mt9t112_reg_write(client, a, b))
+#define mt9t112_mcu_write(ret, client, a, b) \
+       ECHECKER(ret, __mt9t112_mcu_write(client, a, b))
+
+#define mt9t112_reg_mask_set(ret, client, a, b, c) \
+       ECHECKER(ret, __mt9t112_reg_mask_set(client, a, b, c))
+#define mt9t112_mcu_mask_set(ret, client, a, b, c) \
+       ECHECKER(ret, __mt9t112_mcu_mask_set(client, a, b, c))
+
+#define mt9t112_reg_read(ret, client, a) \
+       ECHECKER(ret, __mt9t112_reg_read(client, a))
+
+/*
+ * Logical address
+ */
+#define _VAR(id, offset, base) (base | (id & 0x1f) << 10 | (offset & 0x3ff))
+#define VAR(id, offset)  _VAR(id, offset, 0x0000)
+#define VAR8(id, offset) _VAR(id, offset, 0x8000)
+
+/************************************************************************
+                       struct
+************************************************************************/
+struct mt9t112_format {
+       u32 code;
+       enum v4l2_colorspace colorspace;
+       u16 fmt;
+       u16 order;
+};
+
+struct mt9t112_priv {
+       struct v4l2_subdev               subdev;
+       struct mt9t112_platform_data    *info;
+       struct i2c_client               *client;
+       struct v4l2_rect                 frame;
+       struct v4l2_clk                 *clk;
+       const struct mt9t112_format     *format;
+       int                              num_formats;
+       u32                              flags;
+/* for flags */
+#define INIT_DONE      (1 << 0)
+#define PCLK_RISING    (1 << 1)
+};
+
+/************************************************************************
+                       supported format
+************************************************************************/
+
+static const struct mt9t112_format mt9t112_cfmts[] = {
+       {
+               .code           = MEDIA_BUS_FMT_UYVY8_2X8,
+               .colorspace     = V4L2_COLORSPACE_SRGB,
+               .fmt            = 1,
+               .order          = 0,
+       }, {
+               .code           = MEDIA_BUS_FMT_VYUY8_2X8,
+               .colorspace     = V4L2_COLORSPACE_SRGB,
+               .fmt            = 1,
+               .order          = 1,
+       }, {
+               .code           = MEDIA_BUS_FMT_YUYV8_2X8,
+               .colorspace     = V4L2_COLORSPACE_SRGB,
+               .fmt            = 1,
+               .order          = 2,
+       }, {
+               .code           = MEDIA_BUS_FMT_YVYU8_2X8,
+               .colorspace     = V4L2_COLORSPACE_SRGB,
+               .fmt            = 1,
+               .order          = 3,
+       }, {
+               .code           = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE,
+               .colorspace     = V4L2_COLORSPACE_SRGB,
+               .fmt            = 8,
+               .order          = 2,
+       }, {
+               .code           = MEDIA_BUS_FMT_RGB565_2X8_LE,
+               .colorspace     = V4L2_COLORSPACE_SRGB,
+               .fmt            = 4,
+               .order          = 2,
+       },
+};
+
+/************************************************************************
+                       general function
+************************************************************************/
+static struct mt9t112_priv *to_mt9t112(const struct i2c_client *client)
+{
+       return container_of(i2c_get_clientdata(client),
+                           struct mt9t112_priv,
+                           subdev);
+}
+
+static int __mt9t112_reg_read(const struct i2c_client *client, u16 command)
+{
+       struct i2c_msg msg[2];
+       u8 buf[2];
+       int ret;
+
+       command = swab16(command);
+
+       msg[0].addr  = client->addr;
+       msg[0].flags = 0;
+       msg[0].len   = 2;
+       msg[0].buf   = (u8 *)&command;
+
+       msg[1].addr  = client->addr;
+       msg[1].flags = I2C_M_RD;
+       msg[1].len   = 2;
+       msg[1].buf   = buf;
+
+       /*
+        * if return value of this function is < 0,
+        * it mean error.
+        * else, under 16bit is valid data.
+        */
+       ret = i2c_transfer(client->adapter, msg, 2);
+       if (ret < 0)
+               return ret;
+
+       memcpy(&ret, buf, 2);
+       return swab16(ret);
+}
+
+static int __mt9t112_reg_write(const struct i2c_client *client,
+                              u16 command, u16 data)
+{
+       struct i2c_msg msg;
+       u8 buf[4];
+       int ret;
+
+       command = swab16(command);
+       data = swab16(data);
+
+       memcpy(buf + 0, &command, 2);
+       memcpy(buf + 2, &data,    2);
+
+       msg.addr  = client->addr;
+       msg.flags = 0;
+       msg.len   = 4;
+       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;
+}
+
+static int __mt9t112_reg_mask_set(const struct i2c_client *client,
+                                 u16  command,
+                                 u16  mask,
+                                 u16  set)
+{
+       int val = __mt9t112_reg_read(client, command);
+       if (val < 0)
+               return val;
+
+       val &= ~mask;
+       val |= set & mask;
+
+       return __mt9t112_reg_write(client, command, val);
+}
+
+/* mcu access */
+static int __mt9t112_mcu_read(const struct i2c_client *client, u16 command)
+{
+       int ret;
+
+       ret = __mt9t112_reg_write(client, 0x098E, command);
+       if (ret < 0)
+               return ret;
+
+       return __mt9t112_reg_read(client, 0x0990);
+}
+
+static int __mt9t112_mcu_write(const struct i2c_client *client,
+                              u16 command, u16 data)
+{
+       int ret;
+
+       ret = __mt9t112_reg_write(client, 0x098E, command);
+       if (ret < 0)
+               return ret;
+
+       return __mt9t112_reg_write(client, 0x0990, data);
+}
+
+static int __mt9t112_mcu_mask_set(const struct i2c_client *client,
+                                 u16  command,
+                                 u16  mask,
+                                 u16  set)
+{
+       int val = __mt9t112_mcu_read(client, command);
+       if (val < 0)
+               return val;
+
+       val &= ~mask;
+       val |= set & mask;
+
+       return __mt9t112_mcu_write(client, command, val);
+}
+
+static int mt9t112_reset(const struct i2c_client *client)
+{
+       int ret;
+
+       mt9t112_reg_mask_set(ret, client, 0x001a, 0x0001, 0x0001);
+       msleep(1);
+       mt9t112_reg_mask_set(ret, client, 0x001a, 0x0001, 0x0000);
+
+       return ret;
+}
+
+#ifndef EXT_CLOCK
+#define CLOCK_INFO(a, b)
+#else
+#define CLOCK_INFO(a, b) mt9t112_clock_info(a, b)
+static int mt9t112_clock_info(const struct i2c_client *client, u32 ext)
+{
+       int m, n, p1, p2, p3, p4, p5, p6, p7;
+       u32 vco, clk;
+       char *enable;
+
+       ext /= 1000; /* kbyte order */
+
+       mt9t112_reg_read(n, client, 0x0012);
+       p1 = n & 0x000f;
+       n = n >> 4;
+       p2 = n & 0x000f;
+       n = n >> 4;
+       p3 = n & 0x000f;
+
+       mt9t112_reg_read(n, client, 0x002a);
+       p4 = n & 0x000f;
+       n = n >> 4;
+       p5 = n & 0x000f;
+       n = n >> 4;
+       p6 = n & 0x000f;
+
+       mt9t112_reg_read(n, client, 0x002c);
+       p7 = n & 0x000f;
+
+       mt9t112_reg_read(n, client, 0x0010);
+       m = n & 0x00ff;
+       n = (n >> 8) & 0x003f;
+
+       enable = ((6000 > ext) || (54000 < ext)) ? "X" : "";
+       dev_dbg(&client->dev, "EXTCLK          : %10u K %s\n", ext, enable);
+
+       vco = 2 * m * ext / (n+1);
+       enable = ((384000 > vco) || (768000 < vco)) ? "X" : "";
+       dev_dbg(&client->dev, "VCO             : %10u K %s\n", vco, enable);
+
+       clk = vco / (p1+1) / (p2+1);
+       enable = (96000 < clk) ? "X" : "";
+       dev_dbg(&client->dev, "PIXCLK          : %10u K %s\n", clk, enable);
+
+       clk = vco / (p3+1);
+       enable = (768000 < clk) ? "X" : "";
+       dev_dbg(&client->dev, "MIPICLK         : %10u K %s\n", clk, enable);
+
+       clk = vco / (p6+1);
+       enable = (96000 < clk) ? "X" : "";
+       dev_dbg(&client->dev, "MCU CLK         : %10u K %s\n", clk, enable);
+
+       clk = vco / (p5+1);
+       enable = (54000 < clk) ? "X" : "";
+       dev_dbg(&client->dev, "SOC CLK         : %10u K %s\n", clk, enable);
+
+       clk = vco / (p4+1);
+       enable = (70000 < clk) ? "X" : "";
+       dev_dbg(&client->dev, "Sensor CLK      : %10u K %s\n", clk, enable);
+
+       clk = vco / (p7+1);
+       dev_dbg(&client->dev, "External sensor : %10u K\n", clk);
+
+       clk = ext / (n+1);
+       enable = ((2000 > clk) || (24000 < clk)) ? "X" : "";
+       dev_dbg(&client->dev, "PFD             : %10u K %s\n", clk, enable);
+
+       return 0;
+}
+#endif
+
+static void mt9t112_frame_check(u32 *width, u32 *height, u32 *left, u32 *top)
+{
+       soc_camera_limit_side(left, width, 0, 0, MAX_WIDTH);
+       soc_camera_limit_side(top, height, 0, 0, MAX_HEIGHT);
+}
+
+static int mt9t112_set_a_frame_size(const struct i2c_client *client,
+                                  u16 width,
+                                  u16 height)
+{
+       int ret;
+       u16 wstart = (MAX_WIDTH - width) / 2;
+       u16 hstart = (MAX_HEIGHT - height) / 2;
+
+       /* (Context A) Image Width/Height */
+       mt9t112_mcu_write(ret, client, VAR(26, 0), width);
+       mt9t112_mcu_write(ret, client, VAR(26, 2), height);
+
+       /* (Context A) Output Width/Height */
+       mt9t112_mcu_write(ret, client, VAR(18, 43), 8 + width);
+       mt9t112_mcu_write(ret, client, VAR(18, 45), 8 + height);
+
+       /* (Context A) Start Row/Column */
+       mt9t112_mcu_write(ret, client, VAR(18, 2), 4 + hstart);
+       mt9t112_mcu_write(ret, client, VAR(18, 4), 4 + wstart);
+
+       /* (Context A) End Row/Column */
+       mt9t112_mcu_write(ret, client, VAR(18, 6), 11 + height + hstart);
+       mt9t112_mcu_write(ret, client, VAR(18, 8), 11 + width  + wstart);
+
+       mt9t112_mcu_write(ret, client, VAR8(1, 0), 0x06);
+
+       return ret;
+}
+
+static int mt9t112_set_pll_dividers(const struct i2c_client *client,
+                                   u8 m, u8 n,
+                                   u8 p1, u8 p2, u8 p3,
+                                   u8 p4, u8 p5, u8 p6,
+                                   u8 p7)
+{
+       int ret;
+       u16 val;
+
+       /* N/M */
+       val = (n << 8) |
+             (m << 0);
+       mt9t112_reg_mask_set(ret, client, 0x0010, 0x3fff, val);
+
+       /* P1/P2/P3 */
+       val = ((p3 & 0x0F) << 8) |
+             ((p2 & 0x0F) << 4) |
+             ((p1 & 0x0F) << 0);
+       mt9t112_reg_mask_set(ret, client, 0x0012, 0x0fff, val);
+
+       /* P4/P5/P6 */
+       val = (0x7         << 12) |
+             ((p6 & 0x0F) <<  8) |
+             ((p5 & 0x0F) <<  4) |
+             ((p4 & 0x0F) <<  0);
+       mt9t112_reg_mask_set(ret, client, 0x002A, 0x7fff, val);
+
+       /* P7 */
+       val = (0x1         << 12) |
+             ((p7 & 0x0F) <<  0);
+       mt9t112_reg_mask_set(ret, client, 0x002C, 0x100f, val);
+
+       return ret;
+}
+
+static int mt9t112_init_pll(const struct i2c_client *client)
+{
+       struct mt9t112_priv *priv = to_mt9t112(client);
+       int data, i, ret;
+
+       mt9t112_reg_mask_set(ret, client, 0x0014, 0x003, 0x0001);
+
+       /* PLL control: BYPASS PLL = 8517 */
+       mt9t112_reg_write(ret, client, 0x0014, 0x2145);
+
+       /* Replace these registers when new timing parameters are generated */
+       mt9t112_set_pll_dividers(client,
+                                priv->info->divider.m,
+                                priv->info->divider.n,
+                                priv->info->divider.p1,
+                                priv->info->divider.p2,
+                                priv->info->divider.p3,
+                                priv->info->divider.p4,
+                                priv->info->divider.p5,
+                                priv->info->divider.p6,
+                                priv->info->divider.p7);
+
+       /*
+        * TEST_BYPASS  on
+        * PLL_ENABLE   on
+        * SEL_LOCK_DET on
+        * TEST_BYPASS  off
+        */
+       mt9t112_reg_write(ret, client, 0x0014, 0x2525);
+       mt9t112_reg_write(ret, client, 0x0014, 0x2527);
+       mt9t112_reg_write(ret, client, 0x0014, 0x3427);
+       mt9t112_reg_write(ret, client, 0x0014, 0x3027);
+
+       mdelay(10);
+
+       /*
+        * PLL_BYPASS off
+        * Reference clock count
+        * I2C Master Clock Divider
+        */
+       mt9t112_reg_write(ret, client, 0x0014, 0x3046);
+       mt9t112_reg_write(ret, client, 0x0016, 0x0400); /* JPEG initialization workaround */
+       mt9t112_reg_write(ret, client, 0x0022, 0x0190);
+       mt9t112_reg_write(ret, client, 0x3B84, 0x0212);
+
+       /* External sensor clock is PLL bypass */
+       mt9t112_reg_write(ret, client, 0x002E, 0x0500);
+
+       mt9t112_reg_mask_set(ret, client, 0x0018, 0x0002, 0x0002);
+       mt9t112_reg_mask_set(ret, client, 0x3B82, 0x0004, 0x0004);
+
+       /* MCU disabled */
+       mt9t112_reg_mask_set(ret, client, 0x0018, 0x0004, 0x0004);
+
+       /* out of standby */
+       mt9t112_reg_mask_set(ret, client, 0x0018, 0x0001, 0);
+
+       mdelay(50);
+
+       /*
+        * Standby Workaround
+        * Disable Secondary I2C Pads
+        */
+       mt9t112_reg_write(ret, client, 0x0614, 0x0001);
+       mdelay(1);
+       mt9t112_reg_write(ret, client, 0x0614, 0x0001);
+       mdelay(1);
+       mt9t112_reg_write(ret, client, 0x0614, 0x0001);
+       mdelay(1);
+       mt9t112_reg_write(ret, client, 0x0614, 0x0001);
+       mdelay(1);
+       mt9t112_reg_write(ret, client, 0x0614, 0x0001);
+       mdelay(1);
+       mt9t112_reg_write(ret, client, 0x0614, 0x0001);
+       mdelay(1);
+
+       /* poll to verify out of standby. Must Poll this bit */
+       for (i = 0; i < 100; i++) {
+               mt9t112_reg_read(data, client, 0x0018);
+               if (!(0x4000 & data))
+                       break;
+
+               mdelay(10);
+       }
+
+       return ret;
+}
+
+static int mt9t112_init_setting(const struct i2c_client *client)
+{
+
+       int ret;
+
+       /* Adaptive Output Clock (A) */
+       mt9t112_mcu_mask_set(ret, client, VAR(26, 160), 0x0040, 0x0000);
+
+       /* Read Mode (A) */
+       mt9t112_mcu_write(ret, client, VAR(18, 12), 0x0024);
+
+       /* Fine Correction (A) */
+       mt9t112_mcu_write(ret, client, VAR(18, 15), 0x00CC);
+
+       /* Fine IT Min (A) */
+       mt9t112_mcu_write(ret, client, VAR(18, 17), 0x01f1);
+
+       /* Fine IT Max Margin (A) */
+       mt9t112_mcu_write(ret, client, VAR(18, 19), 0x00fF);
+
+       /* Base Frame Lines (A) */
+       mt9t112_mcu_write(ret, client, VAR(18, 29), 0x032D);
+
+       /* Min Line Length (A) */
+       mt9t112_mcu_write(ret, client, VAR(18, 31), 0x073a);
+
+       /* Line Length (A) */
+       mt9t112_mcu_write(ret, client, VAR(18, 37), 0x07d0);
+
+       /* Adaptive Output Clock (B) */
+       mt9t112_mcu_mask_set(ret, client, VAR(27, 160), 0x0040, 0x0000);
+
+       /* Row Start (B) */
+       mt9t112_mcu_write(ret, client, VAR(18, 74), 0x004);
+
+       /* Column Start (B) */
+       mt9t112_mcu_write(ret, client, VAR(18, 76), 0x004);
+
+       /* Row End (B) */
+       mt9t112_mcu_write(ret, client, VAR(18, 78), 0x60B);
+
+       /* Column End (B) */
+       mt9t112_mcu_write(ret, client, VAR(18, 80), 0x80B);
+
+       /* Fine Correction (B) */
+       mt9t112_mcu_write(ret, client, VAR(18, 87), 0x008C);
+
+       /* Fine IT Min (B) */
+       mt9t112_mcu_write(ret, client, VAR(18, 89), 0x01F1);
+
+       /* Fine IT Max Margin (B) */
+       mt9t112_mcu_write(ret, client, VAR(18, 91), 0x00FF);
+
+       /* Base Frame Lines (B) */
+       mt9t112_mcu_write(ret, client, VAR(18, 101), 0x0668);
+
+       /* Min Line Length (B) */
+       mt9t112_mcu_write(ret, client, VAR(18, 103), 0x0AF0);
+
+       /* Line Length (B) */
+       mt9t112_mcu_write(ret, client, VAR(18, 109), 0x0AF0);
+
+       /*
+        * Flicker Dectection registers
+        * This section should be replaced whenever new Timing file is generated
+        * All the following registers need to be replaced
+        * Following registers are generated from Register Wizard but user can
+        * modify them. For detail see auto flicker detection tuning
+        */
+
+       /* FD_FDPERIOD_SELECT */
+       mt9t112_mcu_write(ret, client, VAR8(8, 5), 0x01);
+
+       /* PRI_B_CONFIG_FD_ALGO_RUN */
+       mt9t112_mcu_write(ret, client, VAR(27, 17), 0x0003);
+
+       /* PRI_A_CONFIG_FD_ALGO_RUN */
+       mt9t112_mcu_write(ret, client, VAR(26, 17), 0x0003);
+
+       /*
+        * AFD range detection tuning registers
+        */
+
+       /* search_f1_50 */
+       mt9t112_mcu_write(ret, client, VAR8(18, 165), 0x25);
+
+       /* search_f2_50 */
+       mt9t112_mcu_write(ret, client, VAR8(18, 166), 0x28);
+
+       /* search_f1_60 */
+       mt9t112_mcu_write(ret, client, VAR8(18, 167), 0x2C);
+
+       /* search_f2_60 */
+       mt9t112_mcu_write(ret, client, VAR8(18, 168), 0x2F);
+
+       /* period_50Hz (A) */
+       mt9t112_mcu_write(ret, client, VAR8(18, 68), 0xBA);
+
+       /* secret register by aptina */
+       /* period_50Hz (A MSB) */
+       mt9t112_mcu_write(ret, client, VAR8(18, 303), 0x00);
+
+       /* period_60Hz (A) */
+       mt9t112_mcu_write(ret, client, VAR8(18, 69), 0x9B);
+
+       /* secret register by aptina */
+       /* period_60Hz (A MSB) */
+       mt9t112_mcu_write(ret, client, VAR8(18, 301), 0x00);
+
+       /* period_50Hz (B) */
+       mt9t112_mcu_write(ret, client, VAR8(18, 140), 0x82);
+
+       /* secret register by aptina */
+       /* period_50Hz (B) MSB */
+       mt9t112_mcu_write(ret, client, VAR8(18, 304), 0x00);
+
+       /* period_60Hz (B) */
+       mt9t112_mcu_write(ret, client, VAR8(18, 141), 0x6D);
+
+       /* secret register by aptina */
+       /* period_60Hz (B) MSB */
+       mt9t112_mcu_write(ret, client, VAR8(18, 302), 0x00);
+
+       /* FD Mode */
+       mt9t112_mcu_write(ret, client, VAR8(8, 2), 0x10);
+
+       /* Stat_min */
+       mt9t112_mcu_write(ret, client, VAR8(8, 9), 0x02);
+
+       /* Stat_max */
+       mt9t112_mcu_write(ret, client, VAR8(8, 10), 0x03);
+
+       /* Min_amplitude */
+       mt9t112_mcu_write(ret, client, VAR8(8, 12), 0x0A);
+
+       /* RX FIFO Watermark (A) */
+       mt9t112_mcu_write(ret, client, VAR(18, 70), 0x0014);
+
+       /* RX FIFO Watermark (B) */
+       mt9t112_mcu_write(ret, client, VAR(18, 142), 0x0014);
+
+       /* MCLK: 16MHz
+        * PCLK: 73MHz
+        * CorePixCLK: 36.5 MHz
+        */
+       mt9t112_mcu_write(ret, client, VAR8(18, 0x0044), 133);
+       mt9t112_mcu_write(ret, client, VAR8(18, 0x0045), 110);
+       mt9t112_mcu_write(ret, client, VAR8(18, 0x008c), 130);
+       mt9t112_mcu_write(ret, client, VAR8(18, 0x008d), 108);
+
+       mt9t112_mcu_write(ret, client, VAR8(18, 0x00A5), 27);
+       mt9t112_mcu_write(ret, client, VAR8(18, 0x00a6), 30);
+       mt9t112_mcu_write(ret, client, VAR8(18, 0x00a7), 32);
+       mt9t112_mcu_write(ret, client, VAR8(18, 0x00a8), 35);
+
+       return ret;
+}
+
+static int mt9t112_auto_focus_setting(const struct i2c_client *client)
+{
+       int ret;
+
+       mt9t112_mcu_write(ret, client, VAR(12, 13),     0x000F);
+       mt9t112_mcu_write(ret, client, VAR(12, 23),     0x0F0F);
+       mt9t112_mcu_write(ret, client, VAR8(1, 0),      0x06);
+
+       mt9t112_reg_write(ret, client, 0x0614, 0x0000);
+
+       mt9t112_mcu_write(ret, client, VAR8(1, 0),      0x05);
+       mt9t112_mcu_write(ret, client, VAR8(12, 2),     0x02);
+       mt9t112_mcu_write(ret, client, VAR(12, 3),      0x0002);
+       mt9t112_mcu_write(ret, client, VAR(17, 3),      0x8001);
+       mt9t112_mcu_write(ret, client, VAR(17, 11),     0x0025);
+       mt9t112_mcu_write(ret, client, VAR(17, 13),     0x0193);
+       mt9t112_mcu_write(ret, client, VAR8(17, 33),    0x18);
+       mt9t112_mcu_write(ret, client, VAR8(1, 0),      0x05);
+
+       return ret;
+}
+
+static int mt9t112_auto_focus_trigger(const struct i2c_client *client)
+{
+       int ret;
+
+       mt9t112_mcu_write(ret, client, VAR8(12, 25), 0x01);
+
+       return ret;
+}
+
+static int mt9t112_init_camera(const struct i2c_client *client)
+{
+       int ret;
+
+       ECHECKER(ret, mt9t112_reset(client));
+
+       ECHECKER(ret, mt9t112_init_pll(client));
+
+       ECHECKER(ret, mt9t112_init_setting(client));
+
+       ECHECKER(ret, mt9t112_auto_focus_setting(client));
+
+       mt9t112_reg_mask_set(ret, client, 0x0018, 0x0004, 0);
+
+       /* Analog setting B */
+       mt9t112_reg_write(ret, client, 0x3084, 0x2409);
+       mt9t112_reg_write(ret, client, 0x3092, 0x0A49);
+       mt9t112_reg_write(ret, client, 0x3094, 0x4949);
+       mt9t112_reg_write(ret, client, 0x3096, 0x4950);
+
+       /*
+        * Disable adaptive clock
+        * PRI_A_CONFIG_JPEG_OB_TX_CONTROL_VAR
+        * PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR
+        */
+       mt9t112_mcu_write(ret, client, VAR(26, 160), 0x0A2E);
+       mt9t112_mcu_write(ret, client, VAR(27, 160), 0x0A2E);
+
+       /* Configure STatus in Status_before_length Format and enable header */
+       /* PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR */
+       mt9t112_mcu_write(ret, client, VAR(27, 144), 0x0CB4);
+
+       /* Enable JPEG in context B */
+       /* PRI_B_CONFIG_JPEG_OB_TX_CONTROL_VAR */
+       mt9t112_mcu_write(ret, client, VAR8(27, 142), 0x01);
+
+       /* Disable Dac_TXLO */
+       mt9t112_reg_write(ret, client, 0x316C, 0x350F);
+
+       /* Set max slew rates */
+       mt9t112_reg_write(ret, client, 0x1E, 0x777);
+
+       return ret;
+}
+
+/************************************************************************
+                       v4l2_subdev_core_ops
+************************************************************************/
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int mt9t112_g_register(struct v4l2_subdev *sd,
+                             struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       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,
+                             const struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret;
+
+       mt9t112_reg_write(ret, client, reg->reg, reg->val);
+
+       return ret;
+}
+#endif
+
+static int mt9t112_s_power(struct v4l2_subdev *sd, int on)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct mt9t112_priv *priv = to_mt9t112(client);
+
+       return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
+}
+
+static const struct v4l2_subdev_core_ops mt9t112_subdev_core_ops = {
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .g_register     = mt9t112_g_register,
+       .s_register     = mt9t112_s_register,
+#endif
+       .s_power        = mt9t112_s_power,
+};
+
+
+/************************************************************************
+                       v4l2_subdev_video_ops
+************************************************************************/
+static int mt9t112_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       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 = PCLK_RISING & priv->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 mt9t112_priv *priv,
+                             const struct v4l2_rect *rect,
+                             u32 code)
+{
+       int i;
+
+       /*
+        * get color format
+        */
+       for (i = 0; i < priv->num_formats; i++)
+               if (mt9t112_cfmts[i].code == code)
+                       break;
+
+       if (i == priv->num_formats)
+               return -EINVAL;
+
+       priv->frame  = *rect;
+
+       /*
+        * frame size check
+        */
+       mt9t112_frame_check(&priv->frame.width, &priv->frame.height,
+                           &priv->frame.left, &priv->frame.top);
+
+       priv->format = mt9t112_cfmts + i;
+
+       return 0;
+}
+
+static int mt9t112_get_selection(struct v4l2_subdev *sd,
+               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_selection *sel)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct mt9t112_priv *priv = to_mt9t112(client);
+
+       if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+               return -EINVAL;
+
+       switch (sel->target) {
+       case V4L2_SEL_TGT_CROP_BOUNDS:
+               sel->r.left = 0;
+               sel->r.top = 0;
+               sel->r.width = MAX_WIDTH;
+               sel->r.height = MAX_HEIGHT;
+               return 0;
+       case V4L2_SEL_TGT_CROP:
+               sel->r = priv->frame;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int mt9t112_set_selection(struct v4l2_subdev *sd,
+               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_selection *sel)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct mt9t112_priv *priv = to_mt9t112(client);
+       const struct v4l2_rect *rect = &sel->r;
+
+       if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
+           sel->target != V4L2_SEL_TGT_CROP)
+               return -EINVAL;
+
+       return mt9t112_set_params(priv, rect, priv->format->code);
+}
+
+static int mt9t112_get_fmt(struct v4l2_subdev *sd,
+               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_format *format)
+{
+       struct v4l2_mbus_framefmt *mf = &format->format;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct mt9t112_priv *priv = to_mt9t112(client);
+
+       if (format->pad)
+               return -EINVAL;
+
+       mf->width       = priv->frame.width;
+       mf->height      = priv->frame.height;
+       mf->colorspace  = priv->format->colorspace;
+       mf->code        = priv->format->code;
+       mf->field       = V4L2_FIELD_NONE;
+
+       return 0;
+}
+
+static int mt9t112_s_fmt(struct v4l2_subdev *sd,
+                        struct v4l2_mbus_framefmt *mf)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct mt9t112_priv *priv = to_mt9t112(client);
+       struct v4l2_rect rect = {
+               .width = mf->width,
+               .height = mf->height,
+               .left = priv->frame.left,
+               .top = priv->frame.top,
+       };
+       int ret;
+
+       ret = mt9t112_set_params(priv, &rect, mf->code);
+
+       if (!ret)
+               mf->colorspace = priv->format->colorspace;
+
+       return ret;
+}
+
+static int mt9t112_set_fmt(struct v4l2_subdev *sd,
+               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_format *format)
+{
+       struct v4l2_mbus_framefmt *mf = &format->format;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct mt9t112_priv *priv = to_mt9t112(client);
+       unsigned int top, left;
+       int i;
+
+       if (format->pad)
+               return -EINVAL;
+
+       for (i = 0; i < priv->num_formats; i++)
+               if (mt9t112_cfmts[i].code == mf->code)
+                       break;
+
+       if (i == priv->num_formats) {
+               mf->code = MEDIA_BUS_FMT_UYVY8_2X8;
+               mf->colorspace = V4L2_COLORSPACE_JPEG;
+       } else {
+               mf->colorspace  = mt9t112_cfmts[i].colorspace;
+       }
+
+       mt9t112_frame_check(&mf->width, &mf->height, &left, &top);
+
+       mf->field = V4L2_FIELD_NONE;
+
+       if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+               return mt9t112_s_fmt(sd, mf);
+       cfg->try_fmt = *mf;
+       return 0;
+}
+
+static int mt9t112_enum_mbus_code(struct v4l2_subdev *sd,
+               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_mbus_code_enum *code)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct mt9t112_priv *priv = to_mt9t112(client);
+
+       if (code->pad || code->index >= priv->num_formats)
+               return -EINVAL;
+
+       code->code = mt9t112_cfmts[code->index].code;
+
+       return 0;
+}
+
+static int mt9t112_g_mbus_config(struct v4l2_subdev *sd,
+                                struct v4l2_mbus_config *cfg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+
+       cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_VSYNC_ACTIVE_HIGH |
+               V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_HIGH |
+               V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING;
+       cfg->type = V4L2_MBUS_PARALLEL;
+       cfg->flags = soc_camera_apply_board_flags(ssdd, cfg);
+
+       return 0;
+}
+
+static int mt9t112_s_mbus_config(struct v4l2_subdev *sd,
+                                const struct v4l2_mbus_config *cfg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct mt9t112_priv *priv = to_mt9t112(client);
+
+       if (soc_camera_apply_board_flags(ssdd, cfg) & V4L2_MBUS_PCLK_SAMPLE_RISING)
+               priv->flags |= PCLK_RISING;
+
+       return 0;
+}
+
+static const struct v4l2_subdev_video_ops mt9t112_subdev_video_ops = {
+       .s_stream       = mt9t112_s_stream,
+       .g_mbus_config  = mt9t112_g_mbus_config,
+       .s_mbus_config  = mt9t112_s_mbus_config,
+};
+
+static const struct v4l2_subdev_pad_ops mt9t112_subdev_pad_ops = {
+       .enum_mbus_code = mt9t112_enum_mbus_code,
+       .get_selection  = mt9t112_get_selection,
+       .set_selection  = mt9t112_set_selection,
+       .get_fmt        = mt9t112_get_fmt,
+       .set_fmt        = mt9t112_set_fmt,
+};
+
+/************************************************************************
+                       i2c driver
+************************************************************************/
+static const struct v4l2_subdev_ops mt9t112_subdev_ops = {
+       .core   = &mt9t112_subdev_core_ops,
+       .video  = &mt9t112_subdev_video_ops,
+       .pad    = &mt9t112_subdev_pad_ops,
+};
+
+static int mt9t112_camera_probe(struct i2c_client *client)
+{
+       struct mt9t112_priv *priv = to_mt9t112(client);
+       const char          *devname;
+       int                  chipid;
+       int                  ret;
+
+       ret = mt9t112_s_power(&priv->subdev, 1);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * check and show chip ID
+        */
+       mt9t112_reg_read(chipid, client, 0x0000);
+
+       switch (chipid) {
+       case 0x2680:
+               devname = "mt9t111";
+               priv->num_formats = 1;
+               break;
+       case 0x2682:
+               devname = "mt9t112";
+               priv->num_formats = ARRAY_SIZE(mt9t112_cfmts);
+               break;
+       default:
+               dev_err(&client->dev, "Product ID error %04x\n", chipid);
+               ret = -ENODEV;
+               goto done;
+       }
+
+       dev_info(&client->dev, "%s chip ID %04x\n", devname, chipid);
+
+done:
+       mt9t112_s_power(&priv->subdev, 0);
+       return ret;
+}
+
+static int mt9t112_probe(struct i2c_client *client,
+                        const struct i2c_device_id *did)
+{
+       struct mt9t112_priv *priv;
+       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct v4l2_rect rect = {
+               .width = VGA_WIDTH,
+               .height = VGA_HEIGHT,
+               .left = (MAX_WIDTH - VGA_WIDTH) / 2,
+               .top = (MAX_HEIGHT - VGA_HEIGHT) / 2,
+       };
+       int ret;
+
+       if (!ssdd || !ssdd->drv_priv) {
+               dev_err(&client->dev, "mt9t112: missing platform data!\n");
+               return -EINVAL;
+       }
+
+       priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->info = ssdd->drv_priv;
+
+       v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops);
+
+       priv->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(priv->clk))
+               return PTR_ERR(priv->clk);
+
+       ret = mt9t112_camera_probe(client);
+
+       /* Cannot fail: using the default supported pixel code */
+       if (!ret)
+               mt9t112_set_params(priv, &rect, MEDIA_BUS_FMT_UYVY8_2X8);
+       else
+               v4l2_clk_put(priv->clk);
+
+       return ret;
+}
+
+static int mt9t112_remove(struct i2c_client *client)
+{
+       struct mt9t112_priv *priv = to_mt9t112(client);
+
+       v4l2_clk_put(priv->clk);
+       return 0;
+}
+
+static const struct i2c_device_id mt9t112_id[] = {
+       { "mt9t112", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, mt9t112_id);
+
+static struct i2c_driver mt9t112_i2c_driver = {
+       .driver = {
+               .name = "mt9t112",
+       },
+       .probe    = mt9t112_probe,
+       .remove   = mt9t112_remove,
+       .id_table = mt9t112_id,
+};
+
+module_i2c_driver(mt9t112_i2c_driver);
+
+MODULE_DESCRIPTION("SoC Camera driver for mt9t112");
+MODULE_AUTHOR("Kuninori Morimoto");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/soc_camera/soc_mt9v022.c b/drivers/media/i2c/soc_camera/soc_mt9v022.c
new file mode 100644 (file)
index 0000000..6d922b1
--- /dev/null
@@ -0,0 +1,1012 @@
+/*
+ * Driver for MT9V022 CMOS Image Sensor from Micron
+ *
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * 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.
+ */
+
+#include <linux/videodev2.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/log2.h>
+#include <linux/module.h>
+
+#include <media/i2c/mt9v022.h>
+#include <media/soc_camera.h>
+#include <media/drv-intf/soc_mediabus.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-clk.h>
+#include <media/v4l2-ctrls.h>
+
+/*
+ * mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c
+ * The platform has to define struct i2c_board_info objects and link to them
+ * from struct soc_camera_host_desc
+ */
+
+static char *sensor_type;
+module_param(sensor_type, charp, S_IRUGO);
+MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\"");
+
+/* mt9v022 selected register addresses */
+#define MT9V022_CHIP_VERSION           0x00
+#define MT9V022_COLUMN_START           0x01
+#define MT9V022_ROW_START              0x02
+#define MT9V022_WINDOW_HEIGHT          0x03
+#define MT9V022_WINDOW_WIDTH           0x04
+#define MT9V022_HORIZONTAL_BLANKING    0x05
+#define MT9V022_VERTICAL_BLANKING      0x06
+#define MT9V022_CHIP_CONTROL           0x07
+#define MT9V022_SHUTTER_WIDTH1         0x08
+#define MT9V022_SHUTTER_WIDTH2         0x09
+#define MT9V022_SHUTTER_WIDTH_CTRL     0x0a
+#define MT9V022_TOTAL_SHUTTER_WIDTH    0x0b
+#define MT9V022_RESET                  0x0c
+#define MT9V022_READ_MODE              0x0d
+#define MT9V022_MONITOR_MODE           0x0e
+#define MT9V022_PIXEL_OPERATION_MODE   0x0f
+#define MT9V022_LED_OUT_CONTROL                0x1b
+#define MT9V022_ADC_MODE_CONTROL       0x1c
+#define MT9V022_REG32                  0x20
+#define MT9V022_ANALOG_GAIN            0x35
+#define MT9V022_BLACK_LEVEL_CALIB_CTRL 0x47
+#define MT9V022_PIXCLK_FV_LV           0x74
+#define MT9V022_DIGITAL_TEST_PATTERN   0x7f
+#define MT9V022_AEC_AGC_ENABLE         0xAF
+#define MT9V022_MAX_TOTAL_SHUTTER_WIDTH        0xBD
+
+/* mt9v024 partial list register addresses changes with respect to mt9v022 */
+#define MT9V024_PIXCLK_FV_LV           0x72
+#define MT9V024_MAX_TOTAL_SHUTTER_WIDTH        0xAD
+
+/* Progressive scan, master, defaults */
+#define MT9V022_CHIP_CONTROL_DEFAULT   0x188
+
+#define MT9V022_MAX_WIDTH              752
+#define MT9V022_MAX_HEIGHT             480
+#define MT9V022_MIN_WIDTH              48
+#define MT9V022_MIN_HEIGHT             32
+#define MT9V022_COLUMN_SKIP            1
+#define MT9V022_ROW_SKIP               4
+
+#define MT9V022_HORIZONTAL_BLANKING_MIN        43
+#define MT9V022_HORIZONTAL_BLANKING_MAX        1023
+#define MT9V022_HORIZONTAL_BLANKING_DEF        94
+#define MT9V022_VERTICAL_BLANKING_MIN  2
+#define MT9V022_VERTICAL_BLANKING_MAX  3000
+#define MT9V022_VERTICAL_BLANKING_DEF  45
+
+#define is_mt9v022_rev3(id)    (id == 0x1313)
+#define is_mt9v024(id)         (id == 0x1324)
+
+/* MT9V022 has only one fixed colorspace per pixelcode */
+struct mt9v022_datafmt {
+       u32     code;
+       enum v4l2_colorspace            colorspace;
+};
+
+/* Find a data format by a pixel code in an array */
+static const struct mt9v022_datafmt *mt9v022_find_datafmt(
+       u32 code, const struct mt9v022_datafmt *fmt,
+       int n)
+{
+       int i;
+       for (i = 0; i < n; i++)
+               if (fmt[i].code == code)
+                       return fmt + i;
+
+       return NULL;
+}
+
+static const struct mt9v022_datafmt mt9v022_colour_fmts[] = {
+       /*
+        * Order important: first natively supported,
+        * second supported with a GPIO extender
+        */
+       {MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB},
+       {MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
+};
+
+static const struct mt9v022_datafmt mt9v022_monochrome_fmts[] = {
+       /* Order important - see above */
+       {MEDIA_BUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG},
+       {MEDIA_BUS_FMT_Y8_1X8, V4L2_COLORSPACE_JPEG},
+};
+
+/* only registers with different addresses on different mt9v02x sensors */
+struct mt9v02x_register {
+       u8      max_total_shutter_width;
+       u8      pixclk_fv_lv;
+};
+
+static const struct mt9v02x_register mt9v022_register = {
+       .max_total_shutter_width        = MT9V022_MAX_TOTAL_SHUTTER_WIDTH,
+       .pixclk_fv_lv                   = MT9V022_PIXCLK_FV_LV,
+};
+
+static const struct mt9v02x_register mt9v024_register = {
+       .max_total_shutter_width        = MT9V024_MAX_TOTAL_SHUTTER_WIDTH,
+       .pixclk_fv_lv                   = MT9V024_PIXCLK_FV_LV,
+};
+
+enum mt9v022_model {
+       MT9V022IX7ATM,
+       MT9V022IX7ATC,
+};
+
+struct mt9v022 {
+       struct v4l2_subdev subdev;
+       struct v4l2_ctrl_handler hdl;
+       struct {
+               /* exposure/auto-exposure cluster */
+               struct v4l2_ctrl *autoexposure;
+               struct v4l2_ctrl *exposure;
+       };
+       struct {
+               /* gain/auto-gain cluster */
+               struct v4l2_ctrl *autogain;
+               struct v4l2_ctrl *gain;
+       };
+       struct v4l2_ctrl *hblank;
+       struct v4l2_ctrl *vblank;
+       struct v4l2_rect rect;  /* Sensor window */
+       struct v4l2_clk *clk;
+       const struct mt9v022_datafmt *fmt;
+       const struct mt9v022_datafmt *fmts;
+       const struct mt9v02x_register *reg;
+       int num_fmts;
+       enum mt9v022_model model;
+       u16 chip_control;
+       u16 chip_version;
+       unsigned short y_skip_top;      /* Lines to skip at the top */
+};
+
+static struct mt9v022 *to_mt9v022(const struct i2c_client *client)
+{
+       return container_of(i2c_get_clientdata(client), struct mt9v022, subdev);
+}
+
+static int reg_read(struct i2c_client *client, const u8 reg)
+{
+       return i2c_smbus_read_word_swapped(client, reg);
+}
+
+static int reg_write(struct i2c_client *client, const u8 reg,
+                    const u16 data)
+{
+       return i2c_smbus_write_word_swapped(client, reg, data);
+}
+
+static int reg_set(struct i2c_client *client, const u8 reg,
+                  const u16 data)
+{
+       int ret;
+
+       ret = reg_read(client, reg);
+       if (ret < 0)
+               return ret;
+       return reg_write(client, reg, ret | data);
+}
+
+static int reg_clear(struct i2c_client *client, const u8 reg,
+                    const u16 data)
+{
+       int ret;
+
+       ret = reg_read(client, reg);
+       if (ret < 0)
+               return ret;
+       return reg_write(client, reg, ret & ~data);
+}
+
+static int mt9v022_init(struct i2c_client *client)
+{
+       struct mt9v022 *mt9v022 = to_mt9v022(client);
+       int ret;
+
+       /*
+        * Almost the default mode: master, parallel, simultaneous, and an
+        * undocumented bit 0x200, which is present in table 7, but not in 8,
+        * plus snapshot mode to disable scan for now
+        */
+       mt9v022->chip_control |= 0x10;
+       ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
+       if (!ret)
+               ret = reg_write(client, MT9V022_READ_MODE, 0x300);
+
+       /* All defaults */
+       if (!ret)
+               /* AEC, AGC on */
+               ret = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x3);
+       if (!ret)
+               ret = reg_write(client, MT9V022_ANALOG_GAIN, 16);
+       if (!ret)
+               ret = reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH, 480);
+       if (!ret)
+               ret = reg_write(client, mt9v022->reg->max_total_shutter_width, 480);
+       if (!ret)
+               /* default - auto */
+               ret = reg_clear(client, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1);
+       if (!ret)
+               ret = reg_write(client, MT9V022_DIGITAL_TEST_PATTERN, 0);
+       if (!ret)
+               return v4l2_ctrl_handler_setup(&mt9v022->hdl);
+
+       return ret;
+}
+
+static int mt9v022_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct mt9v022 *mt9v022 = to_mt9v022(client);
+
+       if (enable) {
+               /* Switch to master "normal" mode */
+               mt9v022->chip_control &= ~0x10;
+               if (is_mt9v022_rev3(mt9v022->chip_version) ||
+                   is_mt9v024(mt9v022->chip_version)) {
+                       /*
+                        * Unset snapshot mode specific settings: clear bit 9
+                        * and bit 2 in reg. 0x20 when in normal mode.
+                        */
+                       if (reg_clear(client, MT9V022_REG32, 0x204))
+                               return -EIO;
+               }
+       } else {
+               /* Switch to snapshot mode */
+               mt9v022->chip_control |= 0x10;
+               if (is_mt9v022_rev3(mt9v022->chip_version) ||
+                   is_mt9v024(mt9v022->chip_version)) {
+                       /*
+                        * Required settings for snapshot mode: set bit 9
+                        * (RST enable) and bit 2 (CR enable) in reg. 0x20
+                        * See TechNote TN0960 or TN-09-225.
+                        */
+                       if (reg_set(client, MT9V022_REG32, 0x204))
+                               return -EIO;
+               }
+       }
+
+       if (reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control) < 0)
+               return -EIO;
+       return 0;
+}
+
+static int mt9v022_set_selection(struct v4l2_subdev *sd,
+               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_selection *sel)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct mt9v022 *mt9v022 = to_mt9v022(client);
+       struct v4l2_rect rect = sel->r;
+       int min_row, min_blank;
+       int ret;
+
+       if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
+           sel->target != V4L2_SEL_TGT_CROP)
+               return -EINVAL;
+
+       /* Bayer format - even size lengths */
+       if (mt9v022->fmts == mt9v022_colour_fmts) {
+               rect.width      = ALIGN(rect.width, 2);
+               rect.height     = ALIGN(rect.height, 2);
+               /* Let the user play with the starting pixel */
+       }
+
+       soc_camera_limit_side(&rect.left, &rect.width,
+                    MT9V022_COLUMN_SKIP, MT9V022_MIN_WIDTH, MT9V022_MAX_WIDTH);
+
+       soc_camera_limit_side(&rect.top, &rect.height,
+                    MT9V022_ROW_SKIP, MT9V022_MIN_HEIGHT, MT9V022_MAX_HEIGHT);
+
+       /* Like in example app. Contradicts the datasheet though */
+       ret = reg_read(client, MT9V022_AEC_AGC_ENABLE);
+       if (ret >= 0) {
+               if (ret & 1) /* Autoexposure */
+                       ret = reg_write(client, mt9v022->reg->max_total_shutter_width,
+                                       rect.height + mt9v022->y_skip_top + 43);
+               /*
+                * If autoexposure is off, there is no need to set
+                * MT9V022_TOTAL_SHUTTER_WIDTH here. Autoexposure can be off
+                * only if the user has set exposure manually, using the
+                * V4L2_CID_EXPOSURE_AUTO with the value V4L2_EXPOSURE_MANUAL.
+                * In this case the register MT9V022_TOTAL_SHUTTER_WIDTH
+                * already contains the correct value.
+                */
+       }
+       /* Setup frame format: defaults apart from width and height */
+       if (!ret)
+               ret = reg_write(client, MT9V022_COLUMN_START, rect.left);
+       if (!ret)
+               ret = reg_write(client, MT9V022_ROW_START, rect.top);
+       /*
+        * mt9v022: min total row time is 660 columns, min blanking is 43
+        * mt9v024: min total row time is 690 columns, min blanking is 61
+        */
+       if (is_mt9v024(mt9v022->chip_version)) {
+               min_row = 690;
+               min_blank = 61;
+       } else {
+               min_row = 660;
+               min_blank = 43;
+       }
+       if (!ret)
+               ret = v4l2_ctrl_s_ctrl(mt9v022->hblank,
+                               rect.width > min_row - min_blank ?
+                               min_blank : min_row - rect.width);
+       if (!ret)
+               ret = v4l2_ctrl_s_ctrl(mt9v022->vblank, 45);
+       if (!ret)
+               ret = reg_write(client, MT9V022_WINDOW_WIDTH, rect.width);
+       if (!ret)
+               ret = reg_write(client, MT9V022_WINDOW_HEIGHT,
+                               rect.height + mt9v022->y_skip_top);
+
+       if (ret < 0)
+               return ret;
+
+       dev_dbg(&client->dev, "Frame %dx%d pixel\n", rect.width, rect.height);
+
+       mt9v022->rect = rect;
+
+       return 0;
+}
+
+static int mt9v022_get_selection(struct v4l2_subdev *sd,
+               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_selection *sel)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct mt9v022 *mt9v022 = to_mt9v022(client);
+
+       if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+               return -EINVAL;
+
+       switch (sel->target) {
+       case V4L2_SEL_TGT_CROP_BOUNDS:
+               sel->r.left = MT9V022_COLUMN_SKIP;
+               sel->r.top = MT9V022_ROW_SKIP;
+               sel->r.width = MT9V022_MAX_WIDTH;
+               sel->r.height = MT9V022_MAX_HEIGHT;
+               return 0;
+       case V4L2_SEL_TGT_CROP:
+               sel->r = mt9v022->rect;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int mt9v022_get_fmt(struct v4l2_subdev *sd,
+               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_format *format)
+{
+       struct v4l2_mbus_framefmt *mf = &format->format;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct mt9v022 *mt9v022 = to_mt9v022(client);
+
+       if (format->pad)
+               return -EINVAL;
+
+       mf->width       = mt9v022->rect.width;
+       mf->height      = mt9v022->rect.height;
+       mf->code        = mt9v022->fmt->code;
+       mf->colorspace  = mt9v022->fmt->colorspace;
+       mf->field       = V4L2_FIELD_NONE;
+
+       return 0;
+}
+
+static int mt9v022_s_fmt(struct v4l2_subdev *sd,
+                        const struct mt9v022_datafmt *fmt,
+                        struct v4l2_mbus_framefmt *mf)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct mt9v022 *mt9v022 = to_mt9v022(client);
+       struct v4l2_subdev_selection sel = {
+               .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+               .target = V4L2_SEL_TGT_CROP,
+               .r.left = mt9v022->rect.left,
+               .r.top = mt9v022->rect.top,
+               .r.width = mf->width,
+               .r.height = mf->height,
+       };
+       int ret;
+
+       /*
+        * The caller provides a supported format, as verified per call to
+        * .set_fmt(FORMAT_TRY), datawidth is from our supported format list
+        */
+       switch (mf->code) {
+       case MEDIA_BUS_FMT_Y8_1X8:
+       case MEDIA_BUS_FMT_Y10_1X10:
+               if (mt9v022->model != MT9V022IX7ATM)
+                       return -EINVAL;
+               break;
+       case MEDIA_BUS_FMT_SBGGR8_1X8:
+       case MEDIA_BUS_FMT_SBGGR10_1X10:
+               if (mt9v022->model != MT9V022IX7ATC)
+                       return -EINVAL;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* No support for scaling on this camera, just crop. */
+       ret = mt9v022_set_selection(sd, NULL, &sel);
+       if (!ret) {
+               mf->width       = mt9v022->rect.width;
+               mf->height      = mt9v022->rect.height;
+               mt9v022->fmt    = fmt;
+               mf->colorspace  = fmt->colorspace;
+       }
+
+       return ret;
+}
+
+static int mt9v022_set_fmt(struct v4l2_subdev *sd,
+               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_format *format)
+{
+       struct v4l2_mbus_framefmt *mf = &format->format;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct mt9v022 *mt9v022 = to_mt9v022(client);
+       const struct mt9v022_datafmt *fmt;
+       int align = mf->code == MEDIA_BUS_FMT_SBGGR8_1X8 ||
+               mf->code == MEDIA_BUS_FMT_SBGGR10_1X10;
+
+       if (format->pad)
+               return -EINVAL;
+
+       v4l_bound_align_image(&mf->width, MT9V022_MIN_WIDTH,
+               MT9V022_MAX_WIDTH, align,
+               &mf->height, MT9V022_MIN_HEIGHT + mt9v022->y_skip_top,
+               MT9V022_MAX_HEIGHT + mt9v022->y_skip_top, align, 0);
+
+       fmt = mt9v022_find_datafmt(mf->code, mt9v022->fmts,
+                                  mt9v022->num_fmts);
+       if (!fmt) {
+               fmt = mt9v022->fmt;
+               mf->code = fmt->code;
+       }
+
+       mf->colorspace  = fmt->colorspace;
+
+       if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+               return mt9v022_s_fmt(sd, fmt, mf);
+       cfg->try_fmt = *mf;
+       return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int mt9v022_g_register(struct v4l2_subdev *sd,
+                             struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (reg->reg > 0xff)
+               return -EINVAL;
+
+       reg->size = 2;
+       reg->val = reg_read(client, reg->reg);
+
+       if (reg->val > 0xffff)
+               return -EIO;
+
+       return 0;
+}
+
+static int mt9v022_s_register(struct v4l2_subdev *sd,
+                             const struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (reg->reg > 0xff)
+               return -EINVAL;
+
+       if (reg_write(client, reg->reg, reg->val) < 0)
+               return -EIO;
+
+       return 0;
+}
+#endif
+
+static int mt9v022_s_power(struct v4l2_subdev *sd, int on)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct mt9v022 *mt9v022 = to_mt9v022(client);
+
+       return soc_camera_set_power(&client->dev, ssdd, mt9v022->clk, on);
+}
+
+static int mt9v022_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct mt9v022 *mt9v022 = container_of(ctrl->handler,
+                                              struct mt9v022, hdl);
+       struct v4l2_subdev *sd = &mt9v022->subdev;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct v4l2_ctrl *gain = mt9v022->gain;
+       struct v4l2_ctrl *exp = mt9v022->exposure;
+       unsigned long range;
+       int data;
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUTOGAIN:
+               data = reg_read(client, MT9V022_ANALOG_GAIN);
+               if (data < 0)
+                       return -EIO;
+
+               range = gain->maximum - gain->minimum;
+               gain->val = ((data - 16) * range + 24) / 48 + gain->minimum;
+               return 0;
+       case V4L2_CID_EXPOSURE_AUTO:
+               data = reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH);
+               if (data < 0)
+                       return -EIO;
+
+               range = exp->maximum - exp->minimum;
+               exp->val = ((data - 1) * range + 239) / 479 + exp->minimum;
+               return 0;
+       case V4L2_CID_HBLANK:
+               data = reg_read(client, MT9V022_HORIZONTAL_BLANKING);
+               if (data < 0)
+                       return -EIO;
+               ctrl->val = data;
+               return 0;
+       case V4L2_CID_VBLANK:
+               data = reg_read(client, MT9V022_VERTICAL_BLANKING);
+               if (data < 0)
+                       return -EIO;
+               ctrl->val = data;
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static int mt9v022_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct mt9v022 *mt9v022 = container_of(ctrl->handler,
+                                              struct mt9v022, hdl);
+       struct v4l2_subdev *sd = &mt9v022->subdev;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int data;
+
+       switch (ctrl->id) {
+       case V4L2_CID_VFLIP:
+               if (ctrl->val)
+                       data = reg_set(client, MT9V022_READ_MODE, 0x10);
+               else
+                       data = reg_clear(client, MT9V022_READ_MODE, 0x10);
+               if (data < 0)
+                       return -EIO;
+               return 0;
+       case V4L2_CID_HFLIP:
+               if (ctrl->val)
+                       data = reg_set(client, MT9V022_READ_MODE, 0x20);
+               else
+                       data = reg_clear(client, MT9V022_READ_MODE, 0x20);
+               if (data < 0)
+                       return -EIO;
+               return 0;
+       case V4L2_CID_AUTOGAIN:
+               if (ctrl->val) {
+                       if (reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0)
+                               return -EIO;
+               } else {
+                       struct v4l2_ctrl *gain = mt9v022->gain;
+                       /* mt9v022 has minimum == default */
+                       unsigned long range = gain->maximum - gain->minimum;
+                       /* Valid values 16 to 64, 32 to 64 must be even. */
+                       unsigned long gain_val = ((gain->val - (s32)gain->minimum) *
+                                             48 + range / 2) / range + 16;
+
+                       if (gain_val >= 32)
+                               gain_val &= ~1;
+
+                       /*
+                        * The user wants to set gain manually, hope, she
+                        * knows, what she's doing... Switch AGC off.
+                        */
+                       if (reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x2) < 0)
+                               return -EIO;
+
+                       dev_dbg(&client->dev, "Setting gain from %d to %lu\n",
+                               reg_read(client, MT9V022_ANALOG_GAIN), gain_val);
+                       if (reg_write(client, MT9V022_ANALOG_GAIN, gain_val) < 0)
+                               return -EIO;
+               }
+               return 0;
+       case V4L2_CID_EXPOSURE_AUTO:
+               if (ctrl->val == V4L2_EXPOSURE_AUTO) {
+                       data = reg_set(client, MT9V022_AEC_AGC_ENABLE, 0x1);
+               } else {
+                       struct v4l2_ctrl *exp = mt9v022->exposure;
+                       unsigned long range = exp->maximum - exp->minimum;
+                       unsigned long shutter = ((exp->val - (s32)exp->minimum) *
+                                       479 + range / 2) / range + 1;
+
+                       /*
+                        * The user wants to set shutter width manually, hope,
+                        * she knows, what she's doing... Switch AEC off.
+                        */
+                       data = reg_clear(client, MT9V022_AEC_AGC_ENABLE, 0x1);
+                       if (data < 0)
+                               return -EIO;
+                       dev_dbg(&client->dev, "Shutter width from %d to %lu\n",
+                                       reg_read(client, MT9V022_TOTAL_SHUTTER_WIDTH),
+                                       shutter);
+                       if (reg_write(client, MT9V022_TOTAL_SHUTTER_WIDTH,
+                                               shutter) < 0)
+                               return -EIO;
+               }
+               return 0;
+       case V4L2_CID_HBLANK:
+               if (reg_write(client, MT9V022_HORIZONTAL_BLANKING,
+                               ctrl->val) < 0)
+                       return -EIO;
+               return 0;
+       case V4L2_CID_VBLANK:
+               if (reg_write(client, MT9V022_VERTICAL_BLANKING,
+                               ctrl->val) < 0)
+                       return -EIO;
+               return 0;
+       }
+       return -EINVAL;
+}
+
+/*
+ * Interface active, can use i2c. If it fails, it can indeed mean, that
+ * this wasn't our capture interface, so, we wait for the right one
+ */
+static int mt9v022_video_probe(struct i2c_client *client)
+{
+       struct mt9v022 *mt9v022 = to_mt9v022(client);
+       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       s32 data;
+       int ret;
+       unsigned long flags;
+
+       ret = mt9v022_s_power(&mt9v022->subdev, 1);
+       if (ret < 0)
+               return ret;
+
+       /* Read out the chip version register */
+       data = reg_read(client, MT9V022_CHIP_VERSION);
+
+       /* must be 0x1311, 0x1313 or 0x1324 */
+       if (data != 0x1311 && data != 0x1313 && data != 0x1324) {
+               ret = -ENODEV;
+               dev_info(&client->dev, "No MT9V022 found, ID register 0x%x\n",
+                        data);
+               goto ei2c;
+       }
+
+       mt9v022->chip_version = data;
+
+       mt9v022->reg = is_mt9v024(data) ? &mt9v024_register :
+                       &mt9v022_register;
+
+       /* Soft reset */
+       ret = reg_write(client, MT9V022_RESET, 1);
+       if (ret < 0)
+               goto ei2c;
+       /* 15 clock cycles */
+       udelay(200);
+       if (reg_read(client, MT9V022_RESET)) {
+               dev_err(&client->dev, "Resetting MT9V022 failed!\n");
+               if (ret > 0)
+                       ret = -EIO;
+               goto ei2c;
+       }
+
+       /* Set monochrome or colour sensor type */
+       if (sensor_type && (!strcmp("colour", sensor_type) ||
+                           !strcmp("color", sensor_type))) {
+               ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 4 | 0x11);
+               mt9v022->model = MT9V022IX7ATC;
+               mt9v022->fmts = mt9v022_colour_fmts;
+       } else {
+               ret = reg_write(client, MT9V022_PIXEL_OPERATION_MODE, 0x11);
+               mt9v022->model = MT9V022IX7ATM;
+               mt9v022->fmts = mt9v022_monochrome_fmts;
+       }
+
+       if (ret < 0)
+               goto ei2c;
+
+       mt9v022->num_fmts = 0;
+
+       /*
+        * This is a 10bit sensor, so by default we only allow 10bit.
+        * The platform may support different bus widths due to
+        * different routing of the data lines.
+        */
+       if (ssdd->query_bus_param)
+               flags = ssdd->query_bus_param(ssdd);
+       else
+               flags = SOCAM_DATAWIDTH_10;
+
+       if (flags & SOCAM_DATAWIDTH_10)
+               mt9v022->num_fmts++;
+       else
+               mt9v022->fmts++;
+
+       if (flags & SOCAM_DATAWIDTH_8)
+               mt9v022->num_fmts++;
+
+       mt9v022->fmt = &mt9v022->fmts[0];
+
+       dev_info(&client->dev, "Detected a MT9V022 chip ID %x, %s sensor\n",
+                data, mt9v022->model == MT9V022IX7ATM ?
+                "monochrome" : "colour");
+
+       ret = mt9v022_init(client);
+       if (ret < 0)
+               dev_err(&client->dev, "Failed to initialise the camera\n");
+
+ei2c:
+       mt9v022_s_power(&mt9v022->subdev, 0);
+       return ret;
+}
+
+static int mt9v022_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct mt9v022 *mt9v022 = to_mt9v022(client);
+
+       *lines = mt9v022->y_skip_top;
+
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops mt9v022_ctrl_ops = {
+       .g_volatile_ctrl = mt9v022_g_volatile_ctrl,
+       .s_ctrl = mt9v022_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = {
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .g_register     = mt9v022_g_register,
+       .s_register     = mt9v022_s_register,
+#endif
+       .s_power        = mt9v022_s_power,
+};
+
+static int mt9v022_enum_mbus_code(struct v4l2_subdev *sd,
+               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_mbus_code_enum *code)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct mt9v022 *mt9v022 = to_mt9v022(client);
+
+       if (code->pad || code->index >= mt9v022->num_fmts)
+               return -EINVAL;
+
+       code->code = mt9v022->fmts[code->index].code;
+       return 0;
+}
+
+static int mt9v022_g_mbus_config(struct v4l2_subdev *sd,
+                               struct v4l2_mbus_config *cfg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+
+       cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE |
+               V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING |
+               V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW |
+               V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW |
+               V4L2_MBUS_DATA_ACTIVE_HIGH;
+       cfg->type = V4L2_MBUS_PARALLEL;
+       cfg->flags = soc_camera_apply_board_flags(ssdd, cfg);
+
+       return 0;
+}
+
+static int mt9v022_s_mbus_config(struct v4l2_subdev *sd,
+                                const struct v4l2_mbus_config *cfg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct mt9v022 *mt9v022 = to_mt9v022(client);
+       unsigned long flags = soc_camera_apply_board_flags(ssdd, cfg);
+       unsigned int bps = soc_mbus_get_fmtdesc(mt9v022->fmt->code)->bits_per_sample;
+       int ret;
+       u16 pixclk = 0;
+
+       if (ssdd->set_bus_param) {
+               ret = ssdd->set_bus_param(ssdd, 1 << (bps - 1));
+               if (ret)
+                       return ret;
+       } else if (bps != 10) {
+               /*
+                * Without board specific bus width settings we only support the
+                * sensors native bus width
+                */
+               return -EINVAL;
+       }
+
+       if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
+               pixclk |= 0x10;
+
+       if (!(flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH))
+               pixclk |= 0x1;
+
+       if (!(flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH))
+               pixclk |= 0x2;
+
+       ret = reg_write(client, mt9v022->reg->pixclk_fv_lv, pixclk);
+       if (ret < 0)
+               return ret;
+
+       if (!(flags & V4L2_MBUS_MASTER))
+               mt9v022->chip_control &= ~0x8;
+
+       ret = reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
+       if (ret < 0)
+               return ret;
+
+       dev_dbg(&client->dev, "Calculated pixclk 0x%x, chip control 0x%x\n",
+               pixclk, mt9v022->chip_control);
+
+       return 0;
+}
+
+static const struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = {
+       .s_stream       = mt9v022_s_stream,
+       .g_mbus_config  = mt9v022_g_mbus_config,
+       .s_mbus_config  = mt9v022_s_mbus_config,
+};
+
+static const struct v4l2_subdev_sensor_ops mt9v022_subdev_sensor_ops = {
+       .g_skip_top_lines       = mt9v022_g_skip_top_lines,
+};
+
+static const struct v4l2_subdev_pad_ops mt9v022_subdev_pad_ops = {
+       .enum_mbus_code = mt9v022_enum_mbus_code,
+       .get_selection  = mt9v022_get_selection,
+       .set_selection  = mt9v022_set_selection,
+       .get_fmt        = mt9v022_get_fmt,
+       .set_fmt        = mt9v022_set_fmt,
+};
+
+static const struct v4l2_subdev_ops mt9v022_subdev_ops = {
+       .core   = &mt9v022_subdev_core_ops,
+       .video  = &mt9v022_subdev_video_ops,
+       .sensor = &mt9v022_subdev_sensor_ops,
+       .pad    = &mt9v022_subdev_pad_ops,
+};
+
+static int mt9v022_probe(struct i2c_client *client,
+                        const struct i2c_device_id *did)
+{
+       struct mt9v022 *mt9v022;
+       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+       struct mt9v022_platform_data *pdata;
+       int ret;
+
+       if (!ssdd) {
+               dev_err(&client->dev, "MT9V022 driver needs platform data\n");
+               return -EINVAL;
+       }
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
+               dev_warn(&adapter->dev,
+                        "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
+               return -EIO;
+       }
+
+       mt9v022 = devm_kzalloc(&client->dev, sizeof(struct mt9v022), GFP_KERNEL);
+       if (!mt9v022)
+               return -ENOMEM;
+
+       pdata = ssdd->drv_priv;
+       v4l2_i2c_subdev_init(&mt9v022->subdev, client, &mt9v022_subdev_ops);
+       v4l2_ctrl_handler_init(&mt9v022->hdl, 6);
+       v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
+                       V4L2_CID_VFLIP, 0, 1, 1, 0);
+       v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
+                       V4L2_CID_HFLIP, 0, 1, 1, 0);
+       mt9v022->autogain = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
+                       V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+       mt9v022->gain = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
+                       V4L2_CID_GAIN, 0, 127, 1, 64);
+
+       /*
+        * Simulated autoexposure. If enabled, we calculate shutter width
+        * ourselves in the driver based on vertical blanking and frame width
+        */
+       mt9v022->autoexposure = v4l2_ctrl_new_std_menu(&mt9v022->hdl,
+                       &mt9v022_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0,
+                       V4L2_EXPOSURE_AUTO);
+       mt9v022->exposure = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
+                       V4L2_CID_EXPOSURE, 1, 255, 1, 255);
+
+       mt9v022->hblank = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
+                       V4L2_CID_HBLANK, MT9V022_HORIZONTAL_BLANKING_MIN,
+                       MT9V022_HORIZONTAL_BLANKING_MAX, 1,
+                       MT9V022_HORIZONTAL_BLANKING_DEF);
+
+       mt9v022->vblank = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops,
+                       V4L2_CID_VBLANK, MT9V022_VERTICAL_BLANKING_MIN,
+                       MT9V022_VERTICAL_BLANKING_MAX, 1,
+                       MT9V022_VERTICAL_BLANKING_DEF);
+
+       mt9v022->subdev.ctrl_handler = &mt9v022->hdl;
+       if (mt9v022->hdl.error) {
+               int err = mt9v022->hdl.error;
+
+               dev_err(&client->dev, "control initialisation err %d\n", err);
+               return err;
+       }
+       v4l2_ctrl_auto_cluster(2, &mt9v022->autoexposure,
+                               V4L2_EXPOSURE_MANUAL, true);
+       v4l2_ctrl_auto_cluster(2, &mt9v022->autogain, 0, true);
+
+       mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT;
+
+       /*
+        * On some platforms the first read out line is corrupted.
+        * Workaround it by skipping if indicated by platform data.
+        */
+       mt9v022->y_skip_top     = pdata ? pdata->y_skip_top : 0;
+       mt9v022->rect.left      = MT9V022_COLUMN_SKIP;
+       mt9v022->rect.top       = MT9V022_ROW_SKIP;
+       mt9v022->rect.width     = MT9V022_MAX_WIDTH;
+       mt9v022->rect.height    = MT9V022_MAX_HEIGHT;
+
+       mt9v022->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(mt9v022->clk)) {
+               ret = PTR_ERR(mt9v022->clk);
+               goto eclkget;
+       }
+
+       ret = mt9v022_video_probe(client);
+       if (ret) {
+               v4l2_clk_put(mt9v022->clk);
+eclkget:
+               v4l2_ctrl_handler_free(&mt9v022->hdl);
+       }
+
+       return ret;
+}
+
+static int mt9v022_remove(struct i2c_client *client)
+{
+       struct mt9v022 *mt9v022 = to_mt9v022(client);
+       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+
+       v4l2_clk_put(mt9v022->clk);
+       v4l2_device_unregister_subdev(&mt9v022->subdev);
+       if (ssdd->free_bus)
+               ssdd->free_bus(ssdd);
+       v4l2_ctrl_handler_free(&mt9v022->hdl);
+
+       return 0;
+}
+static const struct i2c_device_id mt9v022_id[] = {
+       { "mt9v022", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, mt9v022_id);
+
+static struct i2c_driver mt9v022_i2c_driver = {
+       .driver = {
+               .name = "mt9v022",
+       },
+       .probe          = mt9v022_probe,
+       .remove         = mt9v022_remove,
+       .id_table       = mt9v022_id,
+};
+
+module_i2c_driver(mt9v022_i2c_driver);
+
+MODULE_DESCRIPTION("Micron MT9V022 Camera driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/soc_camera/soc_ov5642.c b/drivers/media/i2c/soc_camera/soc_ov5642.c
new file mode 100644 (file)
index 0000000..0931898
--- /dev/null
@@ -0,0 +1,1087 @@
+/*
+ * Driver for OV5642 CMOS Image Sensor from Omnivision
+ *
+ * Copyright (C) 2011, Bastian Hecht <hechtb@gmail.com>
+ *
+ * Based on Sony IMX074 Camera Driver
+ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * Based on Omnivision OV7670 Camera Driver
+ * Copyright (C) 2006-7 Jonathan Corbet <corbet@lwn.net>
+ *
+ * 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.
+ */
+
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/module.h>
+#include <linux/v4l2-mediabus.h>
+
+#include <media/soc_camera.h>
+#include <media/v4l2-clk.h>
+#include <media/v4l2-subdev.h>
+
+/* OV5642 registers */
+#define REG_CHIP_ID_HIGH               0x300a
+#define REG_CHIP_ID_LOW                        0x300b
+
+#define REG_WINDOW_START_X_HIGH                0x3800
+#define REG_WINDOW_START_X_LOW         0x3801
+#define REG_WINDOW_START_Y_HIGH                0x3802
+#define REG_WINDOW_START_Y_LOW         0x3803
+#define REG_WINDOW_WIDTH_HIGH          0x3804
+#define REG_WINDOW_WIDTH_LOW           0x3805
+#define REG_WINDOW_HEIGHT_HIGH         0x3806
+#define REG_WINDOW_HEIGHT_LOW          0x3807
+#define REG_OUT_WIDTH_HIGH             0x3808
+#define REG_OUT_WIDTH_LOW              0x3809
+#define REG_OUT_HEIGHT_HIGH            0x380a
+#define REG_OUT_HEIGHT_LOW             0x380b
+#define REG_OUT_TOTAL_WIDTH_HIGH       0x380c
+#define REG_OUT_TOTAL_WIDTH_LOW                0x380d
+#define REG_OUT_TOTAL_HEIGHT_HIGH      0x380e
+#define REG_OUT_TOTAL_HEIGHT_LOW       0x380f
+#define REG_OUTPUT_FORMAT              0x4300
+#define REG_ISP_CTRL_01                        0x5001
+#define REG_AVG_WINDOW_END_X_HIGH      0x5682
+#define REG_AVG_WINDOW_END_X_LOW       0x5683
+#define REG_AVG_WINDOW_END_Y_HIGH      0x5686
+#define REG_AVG_WINDOW_END_Y_LOW       0x5687
+
+/* active pixel array size */
+#define OV5642_SENSOR_SIZE_X   2592
+#define OV5642_SENSOR_SIZE_Y   1944
+
+/*
+ * About OV5642 resolution, cropping and binning:
+ * This sensor supports it all, at least in the feature description.
+ * Unfortunately, no combination of appropriate registers settings could make
+ * the chip work the intended way. As it works with predefined register lists,
+ * some undocumented registers are presumably changed there to achieve their
+ * goals.
+ * This driver currently only works for resolutions up to 720 lines with a
+ * 1:1 scale. Hopefully these restrictions will be removed in the future.
+ */
+#define OV5642_MAX_WIDTH       OV5642_SENSOR_SIZE_X
+#define OV5642_MAX_HEIGHT      720
+
+/* default sizes */
+#define OV5642_DEFAULT_WIDTH   1280
+#define OV5642_DEFAULT_HEIGHT  OV5642_MAX_HEIGHT
+
+/* minimum extra blanking */
+#define BLANKING_EXTRA_WIDTH           500
+#define BLANKING_EXTRA_HEIGHT          20
+
+/*
+ * the sensor's autoexposure is buggy when setting total_height low.
+ * It tries to expose longer than 1 frame period without taking care of it
+ * and this leads to weird output. So we set 1000 lines as minimum.
+ */
+#define BLANKING_MIN_HEIGHT            1000
+
+struct regval_list {
+       u16 reg_num;
+       u8 value;
+};
+
+static struct regval_list ov5642_default_regs_init[] = {
+       { 0x3103, 0x93 },
+       { 0x3008, 0x82 },
+       { 0x3017, 0x7f },
+       { 0x3018, 0xfc },
+       { 0x3810, 0xc2 },
+       { 0x3615, 0xf0 },
+       { 0x3000, 0x0  },
+       { 0x3001, 0x0  },
+       { 0x3002, 0x0  },
+       { 0x3003, 0x0  },
+       { 0x3004, 0xff },
+       { 0x3030, 0x2b },
+       { 0x3011, 0x8  },
+       { 0x3010, 0x10 },
+       { 0x3604, 0x60 },
+       { 0x3622, 0x60 },
+       { 0x3621, 0x9  },
+       { 0x3709, 0x0  },
+       { 0x4000, 0x21 },
+       { 0x401d, 0x22 },
+       { 0x3600, 0x54 },
+       { 0x3605, 0x4  },
+       { 0x3606, 0x3f },
+       { 0x3c01, 0x80 },
+       { 0x300d, 0x22 },
+       { 0x3623, 0x22 },
+       { 0x5000, 0x4f },
+       { 0x5020, 0x4  },
+       { 0x5181, 0x79 },
+       { 0x5182, 0x0  },
+       { 0x5185, 0x22 },
+       { 0x5197, 0x1  },
+       { 0x5500, 0xa  },
+       { 0x5504, 0x0  },
+       { 0x5505, 0x7f },
+       { 0x5080, 0x8  },
+       { 0x300e, 0x18 },
+       { 0x4610, 0x0  },
+       { 0x471d, 0x5  },
+       { 0x4708, 0x6  },
+       { 0x370c, 0xa0 },
+       { 0x5687, 0x94 },
+       { 0x501f, 0x0  },
+       { 0x5000, 0x4f },
+       { 0x5001, 0xcf },
+       { 0x4300, 0x30 },
+       { 0x4300, 0x30 },
+       { 0x460b, 0x35 },
+       { 0x471d, 0x0  },
+       { 0x3002, 0xc  },
+       { 0x3002, 0x0  },
+       { 0x4713, 0x3  },
+       { 0x471c, 0x50 },
+       { 0x4721, 0x2  },
+       { 0x4402, 0x90 },
+       { 0x460c, 0x22 },
+       { 0x3815, 0x44 },
+       { 0x3503, 0x7  },
+       { 0x3501, 0x73 },
+       { 0x3502, 0x80 },
+       { 0x350b, 0x0  },
+       { 0x3818, 0xc8 },
+       { 0x3824, 0x11 },
+       { 0x3a00, 0x78 },
+       { 0x3a1a, 0x4  },
+       { 0x3a13, 0x30 },
+       { 0x3a18, 0x0  },
+       { 0x3a19, 0x7c },
+       { 0x3a08, 0x12 },
+       { 0x3a09, 0xc0 },
+       { 0x3a0a, 0xf  },
+       { 0x3a0b, 0xa0 },
+       { 0x350c, 0x7  },
+       { 0x350d, 0xd0 },
+       { 0x3a0d, 0x8  },
+       { 0x3a0e, 0x6  },
+       { 0x3500, 0x0  },
+       { 0x3501, 0x0  },
+       { 0x3502, 0x0  },
+       { 0x350a, 0x0  },
+       { 0x350b, 0x0  },
+       { 0x3503, 0x0  },
+       { 0x3a0f, 0x3c },
+       { 0x3a10, 0x32 },
+       { 0x3a1b, 0x3c },
+       { 0x3a1e, 0x32 },
+       { 0x3a11, 0x80 },
+       { 0x3a1f, 0x20 },
+       { 0x3030, 0x2b },
+       { 0x3a02, 0x0  },
+       { 0x3a03, 0x7d },
+       { 0x3a04, 0x0  },
+       { 0x3a14, 0x0  },
+       { 0x3a15, 0x7d },
+       { 0x3a16, 0x0  },
+       { 0x3a00, 0x78 },
+       { 0x3a08, 0x9  },
+       { 0x3a09, 0x60 },
+       { 0x3a0a, 0x7  },
+       { 0x3a0b, 0xd0 },
+       { 0x3a0d, 0x10 },
+       { 0x3a0e, 0xd  },
+       { 0x4407, 0x4  },
+       { 0x5193, 0x70 },
+       { 0x589b, 0x0  },
+       { 0x589a, 0xc0 },
+       { 0x401e, 0x20 },
+       { 0x4001, 0x42 },
+       { 0x401c, 0x6  },
+       { 0x3825, 0xac },
+       { 0x3827, 0xc  },
+       { 0x528a, 0x1  },
+       { 0x528b, 0x4  },
+       { 0x528c, 0x8  },
+       { 0x528d, 0x10 },
+       { 0x528e, 0x20 },
+       { 0x528f, 0x28 },
+       { 0x5290, 0x30 },
+       { 0x5292, 0x0  },
+       { 0x5293, 0x1  },
+       { 0x5294, 0x0  },
+       { 0x5295, 0x4  },
+       { 0x5296, 0x0  },
+       { 0x5297, 0x8  },
+       { 0x5298, 0x0  },
+       { 0x5299, 0x10 },
+       { 0x529a, 0x0  },
+       { 0x529b, 0x20 },
+       { 0x529c, 0x0  },
+       { 0x529d, 0x28 },
+       { 0x529e, 0x0  },
+       { 0x529f, 0x30 },
+       { 0x5282, 0x0  },
+       { 0x5300, 0x0  },
+       { 0x5301, 0x20 },
+       { 0x5302, 0x0  },
+       { 0x5303, 0x7c },
+       { 0x530c, 0x0  },
+       { 0x530d, 0xc  },
+       { 0x530e, 0x20 },
+       { 0x530f, 0x80 },
+       { 0x5310, 0x20 },
+       { 0x5311, 0x80 },
+       { 0x5308, 0x20 },
+       { 0x5309, 0x40 },
+       { 0x5304, 0x0  },
+       { 0x5305, 0x30 },
+       { 0x5306, 0x0  },
+       { 0x5307, 0x80 },
+       { 0x5314, 0x8  },
+       { 0x5315, 0x20 },
+       { 0x5319, 0x30 },
+       { 0x5316, 0x10 },
+       { 0x5317, 0x0  },
+       { 0x5318, 0x2  },
+       { 0x5380, 0x1  },
+       { 0x5381, 0x0  },
+       { 0x5382, 0x0  },
+       { 0x5383, 0x4e },
+       { 0x5384, 0x0  },
+       { 0x5385, 0xf  },
+       { 0x5386, 0x0  },
+       { 0x5387, 0x0  },
+       { 0x5388, 0x1  },
+       { 0x5389, 0x15 },
+       { 0x538a, 0x0  },
+       { 0x538b, 0x31 },
+       { 0x538c, 0x0  },
+       { 0x538d, 0x0  },
+       { 0x538e, 0x0  },
+       { 0x538f, 0xf  },
+       { 0x5390, 0x0  },
+       { 0x5391, 0xab },
+       { 0x5392, 0x0  },
+       { 0x5393, 0xa2 },
+       { 0x5394, 0x8  },
+       { 0x5480, 0x14 },
+       { 0x5481, 0x21 },
+       { 0x5482, 0x36 },
+       { 0x5483, 0x57 },
+       { 0x5484, 0x65 },
+       { 0x5485, 0x71 },
+       { 0x5486, 0x7d },
+       { 0x5487, 0x87 },
+       { 0x5488, 0x91 },
+       { 0x5489, 0x9a },
+       { 0x548a, 0xaa },
+       { 0x548b, 0xb8 },
+       { 0x548c, 0xcd },
+       { 0x548d, 0xdd },
+       { 0x548e, 0xea },
+       { 0x548f, 0x1d },
+       { 0x5490, 0x5  },
+       { 0x5491, 0x0  },
+       { 0x5492, 0x4  },
+       { 0x5493, 0x20 },
+       { 0x5494, 0x3  },
+       { 0x5495, 0x60 },
+       { 0x5496, 0x2  },
+       { 0x5497, 0xb8 },
+       { 0x5498, 0x2  },
+       { 0x5499, 0x86 },
+       { 0x549a, 0x2  },
+       { 0x549b, 0x5b },
+       { 0x549c, 0x2  },
+       { 0x549d, 0x3b },
+       { 0x549e, 0x2  },
+       { 0x549f, 0x1c },
+       { 0x54a0, 0x2  },
+       { 0x54a1, 0x4  },
+       { 0x54a2, 0x1  },
+       { 0x54a3, 0xed },
+       { 0x54a4, 0x1  },
+       { 0x54a5, 0xc5 },
+       { 0x54a6, 0x1  },
+       { 0x54a7, 0xa5 },
+       { 0x54a8, 0x1  },
+       { 0x54a9, 0x6c },
+       { 0x54aa, 0x1  },
+       { 0x54ab, 0x41 },
+       { 0x54ac, 0x1  },
+       { 0x54ad, 0x20 },
+       { 0x54ae, 0x0  },
+       { 0x54af, 0x16 },
+       { 0x54b0, 0x1  },
+       { 0x54b1, 0x20 },
+       { 0x54b2, 0x0  },
+       { 0x54b3, 0x10 },
+       { 0x54b4, 0x0  },
+       { 0x54b5, 0xf0 },
+       { 0x54b6, 0x0  },
+       { 0x54b7, 0xdf },
+       { 0x5402, 0x3f },
+       { 0x5403, 0x0  },
+       { 0x3406, 0x0  },
+       { 0x5180, 0xff },
+       { 0x5181, 0x52 },
+       { 0x5182, 0x11 },
+       { 0x5183, 0x14 },
+       { 0x5184, 0x25 },
+       { 0x5185, 0x24 },
+       { 0x5186, 0x6  },
+       { 0x5187, 0x8  },
+       { 0x5188, 0x8  },
+       { 0x5189, 0x7c },
+       { 0x518a, 0x60 },
+       { 0x518b, 0xb2 },
+       { 0x518c, 0xb2 },
+       { 0x518d, 0x44 },
+       { 0x518e, 0x3d },
+       { 0x518f, 0x58 },
+       { 0x5190, 0x46 },
+       { 0x5191, 0xf8 },
+       { 0x5192, 0x4  },
+       { 0x5193, 0x70 },
+       { 0x5194, 0xf0 },
+       { 0x5195, 0xf0 },
+       { 0x5196, 0x3  },
+       { 0x5197, 0x1  },
+       { 0x5198, 0x4  },
+       { 0x5199, 0x12 },
+       { 0x519a, 0x4  },
+       { 0x519b, 0x0  },
+       { 0x519c, 0x6  },
+       { 0x519d, 0x82 },
+       { 0x519e, 0x0  },
+       { 0x5025, 0x80 },
+       { 0x3a0f, 0x38 },
+       { 0x3a10, 0x30 },
+       { 0x3a1b, 0x3a },
+       { 0x3a1e, 0x2e },
+       { 0x3a11, 0x60 },
+       { 0x3a1f, 0x10 },
+       { 0x5688, 0xa6 },
+       { 0x5689, 0x6a },
+       { 0x568a, 0xea },
+       { 0x568b, 0xae },
+       { 0x568c, 0xa6 },
+       { 0x568d, 0x6a },
+       { 0x568e, 0x62 },
+       { 0x568f, 0x26 },
+       { 0x5583, 0x40 },
+       { 0x5584, 0x40 },
+       { 0x5580, 0x2  },
+       { 0x5000, 0xcf },
+       { 0x5800, 0x27 },
+       { 0x5801, 0x19 },
+       { 0x5802, 0x12 },
+       { 0x5803, 0xf  },
+       { 0x5804, 0x10 },
+       { 0x5805, 0x15 },
+       { 0x5806, 0x1e },
+       { 0x5807, 0x2f },
+       { 0x5808, 0x15 },
+       { 0x5809, 0xd  },
+       { 0x580a, 0xa  },
+       { 0x580b, 0x9  },
+       { 0x580c, 0xa  },
+       { 0x580d, 0xc  },
+       { 0x580e, 0x12 },
+       { 0x580f, 0x19 },
+       { 0x5810, 0xb  },
+       { 0x5811, 0x7  },
+       { 0x5812, 0x4  },
+       { 0x5813, 0x3  },
+       { 0x5814, 0x3  },
+       { 0x5815, 0x6  },
+       { 0x5816, 0xa  },
+       { 0x5817, 0xf  },
+       { 0x5818, 0xa  },
+       { 0x5819, 0x5  },
+       { 0x581a, 0x1  },
+       { 0x581b, 0x0  },
+       { 0x581c, 0x0  },
+       { 0x581d, 0x3  },
+       { 0x581e, 0x8  },
+       { 0x581f, 0xc  },
+       { 0x5820, 0xa  },
+       { 0x5821, 0x5  },
+       { 0x5822, 0x1  },
+       { 0x5823, 0x0  },
+       { 0x5824, 0x0  },
+       { 0x5825, 0x3  },
+       { 0x5826, 0x8  },
+       { 0x5827, 0xc  },
+       { 0x5828, 0xe  },
+       { 0x5829, 0x8  },
+       { 0x582a, 0x6  },
+       { 0x582b, 0x4  },
+       { 0x582c, 0x5  },
+       { 0x582d, 0x7  },
+       { 0x582e, 0xb  },
+       { 0x582f, 0x12 },
+       { 0x5830, 0x18 },
+       { 0x5831, 0x10 },
+       { 0x5832, 0xc  },
+       { 0x5833, 0xa  },
+       { 0x5834, 0xb  },
+       { 0x5835, 0xe  },
+       { 0x5836, 0x15 },
+       { 0x5837, 0x19 },
+       { 0x5838, 0x32 },
+       { 0x5839, 0x1f },
+       { 0x583a, 0x18 },
+       { 0x583b, 0x16 },
+       { 0x583c, 0x17 },
+       { 0x583d, 0x1e },
+       { 0x583e, 0x26 },
+       { 0x583f, 0x53 },
+       { 0x5840, 0x10 },
+       { 0x5841, 0xf  },
+       { 0x5842, 0xd  },
+       { 0x5843, 0xc  },
+       { 0x5844, 0xe  },
+       { 0x5845, 0x9  },
+       { 0x5846, 0x11 },
+       { 0x5847, 0x10 },
+       { 0x5848, 0x10 },
+       { 0x5849, 0x10 },
+       { 0x584a, 0x10 },
+       { 0x584b, 0xe  },
+       { 0x584c, 0x10 },
+       { 0x584d, 0x10 },
+       { 0x584e, 0x11 },
+       { 0x584f, 0x10 },
+       { 0x5850, 0xf  },
+       { 0x5851, 0xc  },
+       { 0x5852, 0xf  },
+       { 0x5853, 0x10 },
+       { 0x5854, 0x10 },
+       { 0x5855, 0xf  },
+       { 0x5856, 0xe  },
+       { 0x5857, 0xb  },
+       { 0x5858, 0x10 },
+       { 0x5859, 0xd  },
+       { 0x585a, 0xd  },
+       { 0x585b, 0xc  },
+       { 0x585c, 0xc  },
+       { 0x585d, 0xc  },
+       { 0x585e, 0xb  },
+       { 0x585f, 0xc  },
+       { 0x5860, 0xc  },
+       { 0x5861, 0xc  },
+       { 0x5862, 0xd  },
+       { 0x5863, 0x8  },
+       { 0x5864, 0x11 },
+       { 0x5865, 0x18 },
+       { 0x5866, 0x18 },
+       { 0x5867, 0x19 },
+       { 0x5868, 0x17 },
+       { 0x5869, 0x19 },
+       { 0x586a, 0x16 },
+       { 0x586b, 0x13 },
+       { 0x586c, 0x13 },
+       { 0x586d, 0x12 },
+       { 0x586e, 0x13 },
+       { 0x586f, 0x16 },
+       { 0x5870, 0x14 },
+       { 0x5871, 0x12 },
+       { 0x5872, 0x10 },
+       { 0x5873, 0x11 },
+       { 0x5874, 0x11 },
+       { 0x5875, 0x16 },
+       { 0x5876, 0x14 },
+       { 0x5877, 0x11 },
+       { 0x5878, 0x10 },
+       { 0x5879, 0xf  },
+       { 0x587a, 0x10 },
+       { 0x587b, 0x14 },
+       { 0x587c, 0x13 },
+       { 0x587d, 0x12 },
+       { 0x587e, 0x11 },
+       { 0x587f, 0x11 },
+       { 0x5880, 0x12 },
+       { 0x5881, 0x15 },
+       { 0x5882, 0x14 },
+       { 0x5883, 0x15 },
+       { 0x5884, 0x15 },
+       { 0x5885, 0x15 },
+       { 0x5886, 0x13 },
+       { 0x5887, 0x17 },
+       { 0x3710, 0x10 },
+       { 0x3632, 0x51 },
+       { 0x3702, 0x10 },
+       { 0x3703, 0xb2 },
+       { 0x3704, 0x18 },
+       { 0x370b, 0x40 },
+       { 0x370d, 0x3  },
+       { 0x3631, 0x1  },
+       { 0x3632, 0x52 },
+       { 0x3606, 0x24 },
+       { 0x3620, 0x96 },
+       { 0x5785, 0x7  },
+       { 0x3a13, 0x30 },
+       { 0x3600, 0x52 },
+       { 0x3604, 0x48 },
+       { 0x3606, 0x1b },
+       { 0x370d, 0xb  },
+       { 0x370f, 0xc0 },
+       { 0x3709, 0x1  },
+       { 0x3823, 0x0  },
+       { 0x5007, 0x0  },
+       { 0x5009, 0x0  },
+       { 0x5011, 0x0  },
+       { 0x5013, 0x0  },
+       { 0x519e, 0x0  },
+       { 0x5086, 0x0  },
+       { 0x5087, 0x0  },
+       { 0x5088, 0x0  },
+       { 0x5089, 0x0  },
+       { 0x302b, 0x0  },
+       { 0x3503, 0x7  },
+       { 0x3011, 0x8  },
+       { 0x350c, 0x2  },
+       { 0x350d, 0xe4 },
+       { 0x3621, 0xc9 },
+       { 0x370a, 0x81 },
+       { 0xffff, 0xff },
+};
+
+static struct regval_list ov5642_default_regs_finalise[] = {
+       { 0x3810, 0xc2 },
+       { 0x3818, 0xc9 },
+       { 0x381c, 0x10 },
+       { 0x381d, 0xa0 },
+       { 0x381e, 0x5  },
+       { 0x381f, 0xb0 },
+       { 0x3820, 0x0  },
+       { 0x3821, 0x0  },
+       { 0x3824, 0x11 },
+       { 0x3a08, 0x1b },
+       { 0x3a09, 0xc0 },
+       { 0x3a0a, 0x17 },
+       { 0x3a0b, 0x20 },
+       { 0x3a0d, 0x2  },
+       { 0x3a0e, 0x1  },
+       { 0x401c, 0x4  },
+       { 0x5682, 0x5  },
+       { 0x5683, 0x0  },
+       { 0x5686, 0x2  },
+       { 0x5687, 0xcc },
+       { 0x5001, 0x4f },
+       { 0x589b, 0x6  },
+       { 0x589a, 0xc5 },
+       { 0x3503, 0x0  },
+       { 0x460c, 0x20 },
+       { 0x460b, 0x37 },
+       { 0x471c, 0xd0 },
+       { 0x471d, 0x5  },
+       { 0x3815, 0x1  },
+       { 0x3818, 0xc1 },
+       { 0x501f, 0x0  },
+       { 0x5002, 0xe0 },
+       { 0x4300, 0x32 }, /* UYVY */
+       { 0x3002, 0x1c },
+       { 0x4800, 0x14 },
+       { 0x4801, 0xf  },
+       { 0x3007, 0x3b },
+       { 0x300e, 0x4  },
+       { 0x4803, 0x50 },
+       { 0x3815, 0x1  },
+       { 0x4713, 0x2  },
+       { 0x4842, 0x1  },
+       { 0x300f, 0xe  },
+       { 0x3003, 0x3  },
+       { 0x3003, 0x1  },
+       { 0xffff, 0xff },
+};
+
+struct ov5642_datafmt {
+       u32     code;
+       enum v4l2_colorspace            colorspace;
+};
+
+struct ov5642 {
+       struct v4l2_subdev              subdev;
+       const struct ov5642_datafmt     *fmt;
+       struct v4l2_rect                crop_rect;
+       struct v4l2_clk                 *clk;
+
+       /* blanking information */
+       int total_width;
+       int total_height;
+};
+
+static const struct ov5642_datafmt ov5642_colour_fmts[] = {
+       {MEDIA_BUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG},
+};
+
+static struct ov5642 *to_ov5642(const struct i2c_client *client)
+{
+       return container_of(i2c_get_clientdata(client), struct ov5642, subdev);
+}
+
+/* Find a data format by a pixel code in an array */
+static const struct ov5642_datafmt
+                       *ov5642_find_datafmt(u32 code)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(ov5642_colour_fmts); i++)
+               if (ov5642_colour_fmts[i].code == code)
+                       return ov5642_colour_fmts + i;
+
+       return NULL;
+}
+
+static int reg_read(struct i2c_client *client, u16 reg, u8 *val)
+{
+       int ret;
+       /* We have 16-bit i2c addresses - care for endianness */
+       unsigned char data[2] = { reg >> 8, reg & 0xff };
+
+       ret = i2c_master_send(client, data, 2);
+       if (ret < 2) {
+               dev_err(&client->dev, "%s: i2c read error, reg: %x\n",
+                       __func__, reg);
+               return ret < 0 ? ret : -EIO;
+       }
+
+       ret = i2c_master_recv(client, val, 1);
+       if (ret < 1) {
+               dev_err(&client->dev, "%s: i2c read error, reg: %x\n",
+                               __func__, reg);
+               return ret < 0 ? ret : -EIO;
+       }
+       return 0;
+}
+
+static int reg_write(struct i2c_client *client, u16 reg, u8 val)
+{
+       int ret;
+       unsigned char data[3] = { reg >> 8, reg & 0xff, val };
+
+       ret = i2c_master_send(client, data, 3);
+       if (ret < 3) {
+               dev_err(&client->dev, "%s: i2c write error, reg: %x\n",
+                       __func__, reg);
+               return ret < 0 ? ret : -EIO;
+       }
+
+       return 0;
+}
+
+/*
+ * convenience function to write 16 bit register values that are split up
+ * into two consecutive high and low parts
+ */
+static int reg_write16(struct i2c_client *client, u16 reg, u16 val16)
+{
+       int ret;
+
+       ret = reg_write(client, reg, val16 >> 8);
+       if (ret)
+               return ret;
+       return reg_write(client, reg + 1, val16 & 0x00ff);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ov5642_get_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret;
+       u8 val;
+
+       if (reg->reg & ~0xffff)
+               return -EINVAL;
+
+       reg->size = 1;
+
+       ret = reg_read(client, reg->reg, &val);
+       if (!ret)
+               reg->val = (__u64)val;
+
+       return ret;
+}
+
+static int ov5642_set_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (reg->reg & ~0xffff || reg->val & ~0xff)
+               return -EINVAL;
+
+       return reg_write(client, reg->reg, reg->val);
+}
+#endif
+
+static int ov5642_write_array(struct i2c_client *client,
+                               struct regval_list *vals)
+{
+       while (vals->reg_num != 0xffff || vals->value != 0xff) {
+               int ret = reg_write(client, vals->reg_num, vals->value);
+               if (ret < 0)
+                       return ret;
+               vals++;
+       }
+       dev_dbg(&client->dev, "Register list loaded\n");
+       return 0;
+}
+
+static int ov5642_set_resolution(struct v4l2_subdev *sd)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct ov5642 *priv = to_ov5642(client);
+       int width = priv->crop_rect.width;
+       int height = priv->crop_rect.height;
+       int total_width = priv->total_width;
+       int total_height = priv->total_height;
+       int start_x = (OV5642_SENSOR_SIZE_X - width) / 2;
+       int start_y = (OV5642_SENSOR_SIZE_Y - height) / 2;
+       int ret;
+
+       /*
+        * This should set the starting point for cropping.
+        * Doesn't work so far.
+        */
+       ret = reg_write16(client, REG_WINDOW_START_X_HIGH, start_x);
+       if (!ret)
+               ret = reg_write16(client, REG_WINDOW_START_Y_HIGH, start_y);
+       if (!ret) {
+               priv->crop_rect.left = start_x;
+               priv->crop_rect.top = start_y;
+       }
+
+       if (!ret)
+               ret = reg_write16(client, REG_WINDOW_WIDTH_HIGH, width);
+       if (!ret)
+               ret = reg_write16(client, REG_WINDOW_HEIGHT_HIGH, height);
+       if (ret)
+               return ret;
+       priv->crop_rect.width = width;
+       priv->crop_rect.height = height;
+
+       /* Set the output window size. Only 1:1 scale is supported so far. */
+       ret = reg_write16(client, REG_OUT_WIDTH_HIGH, width);
+       if (!ret)
+               ret = reg_write16(client, REG_OUT_HEIGHT_HIGH, height);
+
+       /* Total width = output size + blanking */
+       if (!ret)
+               ret = reg_write16(client, REG_OUT_TOTAL_WIDTH_HIGH, total_width);
+       if (!ret)
+               ret = reg_write16(client, REG_OUT_TOTAL_HEIGHT_HIGH, total_height);
+
+       /* Sets the window for AWB calculations */
+       if (!ret)
+               ret = reg_write16(client, REG_AVG_WINDOW_END_X_HIGH, width);
+       if (!ret)
+               ret = reg_write16(client, REG_AVG_WINDOW_END_Y_HIGH, height);
+
+       return ret;
+}
+
+static int ov5642_set_fmt(struct v4l2_subdev *sd,
+               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_format *format)
+{
+       struct v4l2_mbus_framefmt *mf = &format->format;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct ov5642 *priv = to_ov5642(client);
+       const struct ov5642_datafmt *fmt = ov5642_find_datafmt(mf->code);
+
+       if (format->pad)
+               return -EINVAL;
+
+       mf->width = priv->crop_rect.width;
+       mf->height = priv->crop_rect.height;
+
+       if (!fmt) {
+               if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+                       return -EINVAL;
+               mf->code        = ov5642_colour_fmts[0].code;
+               mf->colorspace  = ov5642_colour_fmts[0].colorspace;
+       }
+
+       mf->field       = V4L2_FIELD_NONE;
+
+       if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+               priv->fmt = fmt;
+       else
+               cfg->try_fmt = *mf;
+       return 0;
+}
+
+static int ov5642_get_fmt(struct v4l2_subdev *sd,
+               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_format *format)
+{
+       struct v4l2_mbus_framefmt *mf = &format->format;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct ov5642 *priv = to_ov5642(client);
+
+       const struct ov5642_datafmt *fmt = priv->fmt;
+
+       if (format->pad)
+               return -EINVAL;
+
+       mf->code        = fmt->code;
+       mf->colorspace  = fmt->colorspace;
+       mf->width       = priv->crop_rect.width;
+       mf->height      = priv->crop_rect.height;
+       mf->field       = V4L2_FIELD_NONE;
+
+       return 0;
+}
+
+static int ov5642_enum_mbus_code(struct v4l2_subdev *sd,
+               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_mbus_code_enum *code)
+{
+       if (code->pad || code->index >= ARRAY_SIZE(ov5642_colour_fmts))
+               return -EINVAL;
+
+       code->code = ov5642_colour_fmts[code->index].code;
+       return 0;
+}
+
+static int ov5642_set_selection(struct v4l2_subdev *sd,
+               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_selection *sel)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct ov5642 *priv = to_ov5642(client);
+       struct v4l2_rect rect = sel->r;
+       int ret;
+
+       if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
+           sel->target != V4L2_SEL_TGT_CROP)
+               return -EINVAL;
+
+       v4l_bound_align_image(&rect.width, 48, OV5642_MAX_WIDTH, 1,
+                             &rect.height, 32, OV5642_MAX_HEIGHT, 1, 0);
+
+       priv->crop_rect.width   = rect.width;
+       priv->crop_rect.height  = rect.height;
+       priv->total_width       = rect.width + BLANKING_EXTRA_WIDTH;
+       priv->total_height      = max_t(int, rect.height +
+                                                       BLANKING_EXTRA_HEIGHT,
+                                                       BLANKING_MIN_HEIGHT);
+       priv->crop_rect.width           = rect.width;
+       priv->crop_rect.height          = rect.height;
+
+       ret = ov5642_write_array(client, ov5642_default_regs_init);
+       if (!ret)
+               ret = ov5642_set_resolution(sd);
+       if (!ret)
+               ret = ov5642_write_array(client, ov5642_default_regs_finalise);
+
+       return ret;
+}
+
+static int ov5642_get_selection(struct v4l2_subdev *sd,
+               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_selection *sel)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct ov5642 *priv = to_ov5642(client);
+
+       if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+               return -EINVAL;
+
+       switch (sel->target) {
+       case V4L2_SEL_TGT_CROP_BOUNDS:
+               sel->r.left = 0;
+               sel->r.top = 0;
+               sel->r.width = OV5642_MAX_WIDTH;
+               sel->r.height = OV5642_MAX_HEIGHT;
+               return 0;
+       case V4L2_SEL_TGT_CROP:
+               sel->r = priv->crop_rect;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int ov5642_g_mbus_config(struct v4l2_subdev *sd,
+                               struct v4l2_mbus_config *cfg)
+{
+       cfg->type = V4L2_MBUS_CSI2_DPHY;
+       cfg->flags = V4L2_MBUS_CSI2_2_LANE | V4L2_MBUS_CSI2_CHANNEL_0 |
+                                       V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
+
+       return 0;
+}
+
+static int ov5642_s_power(struct v4l2_subdev *sd, int on)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct ov5642 *priv = to_ov5642(client);
+       int ret;
+
+       if (!on)
+               return soc_camera_power_off(&client->dev, ssdd, priv->clk);
+
+       ret = soc_camera_power_on(&client->dev, ssdd, priv->clk);
+       if (ret < 0)
+               return ret;
+
+       ret = ov5642_write_array(client, ov5642_default_regs_init);
+       if (!ret)
+               ret = ov5642_set_resolution(sd);
+       if (!ret)
+               ret = ov5642_write_array(client, ov5642_default_regs_finalise);
+
+       return ret;
+}
+
+static const struct v4l2_subdev_video_ops ov5642_subdev_video_ops = {
+       .g_mbus_config  = ov5642_g_mbus_config,
+};
+
+static const struct v4l2_subdev_pad_ops ov5642_subdev_pad_ops = {
+       .enum_mbus_code = ov5642_enum_mbus_code,
+       .get_selection  = ov5642_get_selection,
+       .set_selection  = ov5642_set_selection,
+       .get_fmt        = ov5642_get_fmt,
+       .set_fmt        = ov5642_set_fmt,
+};
+
+static const struct v4l2_subdev_core_ops ov5642_subdev_core_ops = {
+       .s_power        = ov5642_s_power,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .g_register     = ov5642_get_register,
+       .s_register     = ov5642_set_register,
+#endif
+};
+
+static const struct v4l2_subdev_ops ov5642_subdev_ops = {
+       .core   = &ov5642_subdev_core_ops,
+       .video  = &ov5642_subdev_video_ops,
+       .pad    = &ov5642_subdev_pad_ops,
+};
+
+static int ov5642_video_probe(struct i2c_client *client)
+{
+       struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+       int ret;
+       u8 id_high, id_low;
+       u16 id;
+
+       ret = ov5642_s_power(subdev, 1);
+       if (ret < 0)
+               return ret;
+
+       /* Read sensor Model ID */
+       ret = reg_read(client, REG_CHIP_ID_HIGH, &id_high);
+       if (ret < 0)
+               goto done;
+
+       id = id_high << 8;
+
+       ret = reg_read(client, REG_CHIP_ID_LOW, &id_low);
+       if (ret < 0)
+               goto done;
+
+       id |= id_low;
+
+       dev_info(&client->dev, "Chip ID 0x%04x detected\n", id);
+
+       if (id != 0x5642) {
+               ret = -ENODEV;
+               goto done;
+       }
+
+       ret = 0;
+
+done:
+       ov5642_s_power(subdev, 0);
+       return ret;
+}
+
+static int ov5642_probe(struct i2c_client *client,
+                       const struct i2c_device_id *did)
+{
+       struct ov5642 *priv;
+       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       int ret;
+
+       if (!ssdd) {
+               dev_err(&client->dev, "OV5642: missing platform data!\n");
+               return -EINVAL;
+       }
+
+       priv = devm_kzalloc(&client->dev, sizeof(struct ov5642), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       v4l2_i2c_subdev_init(&priv->subdev, client, &ov5642_subdev_ops);
+
+       priv->fmt               = &ov5642_colour_fmts[0];
+
+       priv->crop_rect.width   = OV5642_DEFAULT_WIDTH;
+       priv->crop_rect.height  = OV5642_DEFAULT_HEIGHT;
+       priv->crop_rect.left    = (OV5642_MAX_WIDTH - OV5642_DEFAULT_WIDTH) / 2;
+       priv->crop_rect.top     = (OV5642_MAX_HEIGHT - OV5642_DEFAULT_HEIGHT) / 2;
+       priv->total_width = OV5642_DEFAULT_WIDTH + BLANKING_EXTRA_WIDTH;
+       priv->total_height = BLANKING_MIN_HEIGHT;
+
+       priv->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(priv->clk))
+               return PTR_ERR(priv->clk);
+
+       ret = ov5642_video_probe(client);
+       if (ret < 0)
+               v4l2_clk_put(priv->clk);
+
+       return ret;
+}
+
+static int ov5642_remove(struct i2c_client *client)
+{
+       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct ov5642 *priv = to_ov5642(client);
+
+       v4l2_clk_put(priv->clk);
+       if (ssdd->free_bus)
+               ssdd->free_bus(ssdd);
+
+       return 0;
+}
+
+static const struct i2c_device_id ov5642_id[] = {
+       { "ov5642", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ov5642_id);
+
+#if IS_ENABLED(CONFIG_OF)
+static const struct of_device_id ov5642_of_match[] = {
+       { .compatible = "ovti,ov5642" },
+       { },
+};
+MODULE_DEVICE_TABLE(of, ov5642_of_match);
+#endif
+
+static struct i2c_driver ov5642_i2c_driver = {
+       .driver = {
+               .name = "ov5642",
+               .of_match_table = of_match_ptr(ov5642_of_match),
+       },
+       .probe          = ov5642_probe,
+       .remove         = ov5642_remove,
+       .id_table       = ov5642_id,
+};
+
+module_i2c_driver(ov5642_i2c_driver);
+
+MODULE_DESCRIPTION("Omnivision OV5642 Camera driver");
+MODULE_AUTHOR("Bastian Hecht <hechtb@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/soc_camera/soc_ov772x.c b/drivers/media/i2c/soc_camera/soc_ov772x.c
new file mode 100644 (file)
index 0000000..fafd372
--- /dev/null
@@ -0,0 +1,1123 @@
+/*
+ * ov772x Camera Driver
+ *
+ * Copyright (C) 2008 Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * Based on ov7670 and soc_camera_platform driver,
+ *
+ * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
+ * Copyright (C) 2008 Magnus Damm
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/videodev2.h>
+
+#include <media/i2c/ov772x.h>
+#include <media/soc_camera.h>
+#include <media/v4l2-clk.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-image-sizes.h>
+
+/*
+ * register offset
+ */
+#define GAIN        0x00 /* AGC - Gain control gain setting */
+#define BLUE        0x01 /* AWB - Blue channel gain setting */
+#define RED         0x02 /* AWB - Red   channel gain setting */
+#define GREEN       0x03 /* AWB - Green channel gain setting */
+#define COM1        0x04 /* Common control 1 */
+#define BAVG        0x05 /* U/B Average Level */
+#define GAVG        0x06 /* Y/Gb Average Level */
+#define RAVG        0x07 /* V/R Average Level */
+#define AECH        0x08 /* Exposure Value - AEC MSBs */
+#define COM2        0x09 /* Common control 2 */
+#define PID         0x0A /* Product ID Number MSB */
+#define VER         0x0B /* Product ID Number LSB */
+#define COM3        0x0C /* Common control 3 */
+#define COM4        0x0D /* Common control 4 */
+#define COM5        0x0E /* Common control 5 */
+#define COM6        0x0F /* Common control 6 */
+#define AEC         0x10 /* Exposure Value */
+#define CLKRC       0x11 /* Internal clock */
+#define COM7        0x12 /* Common control 7 */
+#define COM8        0x13 /* Common control 8 */
+#define COM9        0x14 /* Common control 9 */
+#define COM10       0x15 /* Common control 10 */
+#define REG16       0x16 /* Register 16 */
+#define HSTART      0x17 /* Horizontal sensor size */
+#define HSIZE       0x18 /* Horizontal frame (HREF column) end high 8-bit */
+#define VSTART      0x19 /* Vertical frame (row) start high 8-bit */
+#define VSIZE       0x1A /* Vertical sensor size */
+#define PSHFT       0x1B /* Data format - pixel delay select */
+#define MIDH        0x1C /* Manufacturer ID byte - high */
+#define MIDL        0x1D /* Manufacturer ID byte - low  */
+#define LAEC        0x1F /* Fine AEC value */
+#define COM11       0x20 /* Common control 11 */
+#define BDBASE      0x22 /* Banding filter Minimum AEC value */
+#define DBSTEP      0x23 /* Banding filter Maximum Setp */
+#define AEW         0x24 /* AGC/AEC - Stable operating region (upper limit) */
+#define AEB         0x25 /* AGC/AEC - Stable operating region (lower limit) */
+#define VPT         0x26 /* AGC/AEC Fast mode operating region */
+#define REG28       0x28 /* Register 28 */
+#define HOUTSIZE    0x29 /* Horizontal data output size MSBs */
+#define EXHCH       0x2A /* Dummy pixel insert MSB */
+#define EXHCL       0x2B /* Dummy pixel insert LSB */
+#define VOUTSIZE    0x2C /* Vertical data output size MSBs */
+#define ADVFL       0x2D /* LSB of insert dummy lines in Vertical direction */
+#define ADVFH       0x2E /* MSG of insert dummy lines in Vertical direction */
+#define YAVE        0x2F /* Y/G Channel Average value */
+#define LUMHTH      0x30 /* Histogram AEC/AGC Luminance high level threshold */
+#define LUMLTH      0x31 /* Histogram AEC/AGC Luminance low  level threshold */
+#define HREF        0x32 /* Image start and size control */
+#define DM_LNL      0x33 /* Dummy line low  8 bits */
+#define DM_LNH      0x34 /* Dummy line high 8 bits */
+#define ADOFF_B     0x35 /* AD offset compensation value for B  channel */
+#define ADOFF_R     0x36 /* AD offset compensation value for R  channel */
+#define ADOFF_GB    0x37 /* AD offset compensation value for Gb channel */
+#define ADOFF_GR    0x38 /* AD offset compensation value for Gr channel */
+#define OFF_B       0x39 /* Analog process B  channel offset value */
+#define OFF_R       0x3A /* Analog process R  channel offset value */
+#define OFF_GB      0x3B /* Analog process Gb channel offset value */
+#define OFF_GR      0x3C /* Analog process Gr channel offset value */
+#define COM12       0x3D /* Common control 12 */
+#define COM13       0x3E /* Common control 13 */
+#define COM14       0x3F /* Common control 14 */
+#define COM15       0x40 /* Common control 15*/
+#define COM16       0x41 /* Common control 16 */
+#define TGT_B       0x42 /* BLC blue channel target value */
+#define TGT_R       0x43 /* BLC red  channel target value */
+#define TGT_GB      0x44 /* BLC Gb   channel target value */
+#define TGT_GR      0x45 /* BLC Gr   channel target value */
+/* for ov7720 */
+#define LCC0        0x46 /* Lens correction control 0 */
+#define LCC1        0x47 /* Lens correction option 1 - X coordinate */
+#define LCC2        0x48 /* Lens correction option 2 - Y coordinate */
+#define LCC3        0x49 /* Lens correction option 3 */
+#define LCC4        0x4A /* Lens correction option 4 - radius of the circular */
+#define LCC5        0x4B /* Lens correction option 5 */
+#define LCC6        0x4C /* Lens correction option 6 */
+/* for ov7725 */
+#define LC_CTR      0x46 /* Lens correction control */
+#define LC_XC       0x47 /* X coordinate of lens correction center relative */
+#define LC_YC       0x48 /* Y coordinate of lens correction center relative */
+#define LC_COEF     0x49 /* Lens correction coefficient */
+#define LC_RADI     0x4A /* Lens correction radius */
+#define LC_COEFB    0x4B /* Lens B channel compensation coefficient */
+#define LC_COEFR    0x4C /* Lens R channel compensation coefficient */
+
+#define FIXGAIN     0x4D /* Analog fix gain amplifer */
+#define AREF0       0x4E /* Sensor reference control */
+#define AREF1       0x4F /* Sensor reference current control */
+#define AREF2       0x50 /* Analog reference control */
+#define AREF3       0x51 /* ADC    reference control */
+#define AREF4       0x52 /* ADC    reference control */
+#define AREF5       0x53 /* ADC    reference control */
+#define AREF6       0x54 /* Analog reference control */
+#define AREF7       0x55 /* Analog reference control */
+#define UFIX        0x60 /* U channel fixed value output */
+#define VFIX        0x61 /* V channel fixed value output */
+#define AWBB_BLK    0x62 /* AWB option for advanced AWB */
+#define AWB_CTRL0   0x63 /* AWB control byte 0 */
+#define DSP_CTRL1   0x64 /* DSP control byte 1 */
+#define DSP_CTRL2   0x65 /* DSP control byte 2 */
+#define DSP_CTRL3   0x66 /* DSP control byte 3 */
+#define DSP_CTRL4   0x67 /* DSP control byte 4 */
+#define AWB_BIAS    0x68 /* AWB BLC level clip */
+#define AWB_CTRL1   0x69 /* AWB control  1 */
+#define AWB_CTRL2   0x6A /* AWB control  2 */
+#define AWB_CTRL3   0x6B /* AWB control  3 */
+#define AWB_CTRL4   0x6C /* AWB control  4 */
+#define AWB_CTRL5   0x6D /* AWB control  5 */
+#define AWB_CTRL6   0x6E /* AWB control  6 */
+#define AWB_CTRL7   0x6F /* AWB control  7 */
+#define AWB_CTRL8   0x70 /* AWB control  8 */
+#define AWB_CTRL9   0x71 /* AWB control  9 */
+#define AWB_CTRL10  0x72 /* AWB control 10 */
+#define AWB_CTRL11  0x73 /* AWB control 11 */
+#define AWB_CTRL12  0x74 /* AWB control 12 */
+#define AWB_CTRL13  0x75 /* AWB control 13 */
+#define AWB_CTRL14  0x76 /* AWB control 14 */
+#define AWB_CTRL15  0x77 /* AWB control 15 */
+#define AWB_CTRL16  0x78 /* AWB control 16 */
+#define AWB_CTRL17  0x79 /* AWB control 17 */
+#define AWB_CTRL18  0x7A /* AWB control 18 */
+#define AWB_CTRL19  0x7B /* AWB control 19 */
+#define AWB_CTRL20  0x7C /* AWB control 20 */
+#define AWB_CTRL21  0x7D /* AWB control 21 */
+#define GAM1        0x7E /* Gamma Curve  1st segment input end point */
+#define GAM2        0x7F /* Gamma Curve  2nd segment input end point */
+#define GAM3        0x80 /* Gamma Curve  3rd segment input end point */
+#define GAM4        0x81 /* Gamma Curve  4th segment input end point */
+#define GAM5        0x82 /* Gamma Curve  5th segment input end point */
+#define GAM6        0x83 /* Gamma Curve  6th segment input end point */
+#define GAM7        0x84 /* Gamma Curve  7th segment input end point */
+#define GAM8        0x85 /* Gamma Curve  8th segment input end point */
+#define GAM9        0x86 /* Gamma Curve  9th segment input end point */
+#define GAM10       0x87 /* Gamma Curve 10th segment input end point */
+#define GAM11       0x88 /* Gamma Curve 11th segment input end point */
+#define GAM12       0x89 /* Gamma Curve 12th segment input end point */
+#define GAM13       0x8A /* Gamma Curve 13th segment input end point */
+#define GAM14       0x8B /* Gamma Curve 14th segment input end point */
+#define GAM15       0x8C /* Gamma Curve 15th segment input end point */
+#define SLOP        0x8D /* Gamma curve highest segment slope */
+#define DNSTH       0x8E /* De-noise threshold */
+#define EDGE_STRNGT 0x8F /* Edge strength  control when manual mode */
+#define EDGE_TRSHLD 0x90 /* Edge threshold control when manual mode */
+#define DNSOFF      0x91 /* Auto De-noise threshold control */
+#define EDGE_UPPER  0x92 /* Edge strength upper limit when Auto mode */
+#define EDGE_LOWER  0x93 /* Edge strength lower limit when Auto mode */
+#define MTX1        0x94 /* Matrix coefficient 1 */
+#define MTX2        0x95 /* Matrix coefficient 2 */
+#define MTX3        0x96 /* Matrix coefficient 3 */
+#define MTX4        0x97 /* Matrix coefficient 4 */
+#define MTX5        0x98 /* Matrix coefficient 5 */
+#define MTX6        0x99 /* Matrix coefficient 6 */
+#define MTX_CTRL    0x9A /* Matrix control */
+#define BRIGHT      0x9B /* Brightness control */
+#define CNTRST      0x9C /* Contrast contrast */
+#define CNTRST_CTRL 0x9D /* Contrast contrast center */
+#define UVAD_J0     0x9E /* Auto UV adjust contrast 0 */
+#define UVAD_J1     0x9F /* Auto UV adjust contrast 1 */
+#define SCAL0       0xA0 /* Scaling control 0 */
+#define SCAL1       0xA1 /* Scaling control 1 */
+#define SCAL2       0xA2 /* Scaling control 2 */
+#define FIFODLYM    0xA3 /* FIFO manual mode delay control */
+#define FIFODLYA    0xA4 /* FIFO auto   mode delay control */
+#define SDE         0xA6 /* Special digital effect control */
+#define USAT        0xA7 /* U component saturation control */
+#define VSAT        0xA8 /* V component saturation control */
+/* for ov7720 */
+#define HUE0        0xA9 /* Hue control 0 */
+#define HUE1        0xAA /* Hue control 1 */
+/* for ov7725 */
+#define HUECOS      0xA9 /* Cosine value */
+#define HUESIN      0xAA /* Sine value */
+
+#define SIGN        0xAB /* Sign bit for Hue and contrast */
+#define DSPAUTO     0xAC /* DSP auto function ON/OFF control */
+
+/*
+ * register detail
+ */
+
+/* COM2 */
+#define SOFT_SLEEP_MODE 0x10   /* Soft sleep mode */
+                               /* Output drive capability */
+#define OCAP_1x         0x00   /* 1x */
+#define OCAP_2x         0x01   /* 2x */
+#define OCAP_3x         0x02   /* 3x */
+#define OCAP_4x         0x03   /* 4x */
+
+/* COM3 */
+#define SWAP_MASK       (SWAP_RGB | SWAP_YUV | SWAP_ML)
+#define IMG_MASK        (VFLIP_IMG | HFLIP_IMG)
+
+#define VFLIP_IMG       0x80   /* Vertical flip image ON/OFF selection */
+#define HFLIP_IMG       0x40   /* Horizontal mirror image ON/OFF selection */
+#define SWAP_RGB        0x20   /* Swap B/R  output sequence in RGB mode */
+#define SWAP_YUV        0x10   /* Swap Y/UV output sequence in YUV mode */
+#define SWAP_ML         0x08   /* Swap output MSB/LSB */
+                               /* Tri-state option for output clock */
+#define NOTRI_CLOCK     0x04   /*   0: Tri-state    at this period */
+                               /*   1: No tri-state at this period */
+                               /* Tri-state option for output data */
+#define NOTRI_DATA      0x02   /*   0: Tri-state    at this period */
+                               /*   1: No tri-state at this period */
+#define SCOLOR_TEST     0x01   /* Sensor color bar test pattern */
+
+/* COM4 */
+                               /* PLL frequency control */
+#define PLL_BYPASS      0x00   /*  00: Bypass PLL */
+#define PLL_4x          0x40   /*  01: PLL 4x */
+#define PLL_6x          0x80   /*  10: PLL 6x */
+#define PLL_8x          0xc0   /*  11: PLL 8x */
+                               /* AEC evaluate window */
+#define AEC_FULL        0x00   /*  00: Full window */
+#define AEC_1p2         0x10   /*  01: 1/2  window */
+#define AEC_1p4         0x20   /*  10: 1/4  window */
+#define AEC_2p3         0x30   /*  11: Low 2/3 window */
+
+/* COM5 */
+#define AFR_ON_OFF      0x80   /* Auto frame rate control ON/OFF selection */
+#define AFR_SPPED       0x40   /* Auto frame rate control speed selection */
+                               /* Auto frame rate max rate control */
+#define AFR_NO_RATE     0x00   /*     No  reduction of frame rate */
+#define AFR_1p2         0x10   /*     Max reduction to 1/2 frame rate */
+#define AFR_1p4         0x20   /*     Max reduction to 1/4 frame rate */
+#define AFR_1p8         0x30   /* Max reduction to 1/8 frame rate */
+                               /* Auto frame rate active point control */
+#define AF_2x           0x00   /*     Add frame when AGC reaches  2x gain */
+#define AF_4x           0x04   /*     Add frame when AGC reaches  4x gain */
+#define AF_8x           0x08   /*     Add frame when AGC reaches  8x gain */
+#define AF_16x          0x0c   /* Add frame when AGC reaches 16x gain */
+                               /* AEC max step control */
+#define AEC_NO_LIMIT    0x01   /*   0 : AEC incease step has limit */
+                               /*   1 : No limit to AEC increase step */
+
+/* COM7 */
+                               /* SCCB Register Reset */
+#define SCCB_RESET      0x80   /*   0 : No change */
+                               /*   1 : Resets all registers to default */
+                               /* Resolution selection */
+#define SLCT_MASK       0x40   /*   Mask of VGA or QVGA */
+#define SLCT_VGA        0x00   /*   0 : VGA */
+#define SLCT_QVGA       0x40   /*   1 : QVGA */
+#define ITU656_ON_OFF   0x20   /* ITU656 protocol ON/OFF selection */
+#define SENSOR_RAW     0x10    /* Sensor RAW */
+                               /* RGB output format control */
+#define FMT_MASK        0x0c   /*      Mask of color format */
+#define FMT_GBR422      0x00   /*      00 : GBR 4:2:2 */
+#define FMT_RGB565      0x04   /*      01 : RGB 565 */
+#define FMT_RGB555      0x08   /*      10 : RGB 555 */
+#define FMT_RGB444      0x0c   /* 11 : RGB 444 */
+                               /* Output format control */
+#define OFMT_MASK       0x03    /*      Mask of output format */
+#define OFMT_YUV        0x00   /*      00 : YUV */
+#define OFMT_P_BRAW     0x01   /*      01 : Processed Bayer RAW */
+#define OFMT_RGB        0x02   /*      10 : RGB */
+#define OFMT_BRAW       0x03   /* 11 : Bayer RAW */
+
+/* COM8 */
+#define FAST_ALGO       0x80   /* Enable fast AGC/AEC algorithm */
+                               /* AEC Setp size limit */
+#define UNLMT_STEP      0x40   /*   0 : Step size is limited */
+                               /*   1 : Unlimited step size */
+#define BNDF_ON_OFF     0x20   /* Banding filter ON/OFF */
+#define AEC_BND         0x10   /* Enable AEC below banding value */
+#define AEC_ON_OFF      0x08   /* Fine AEC ON/OFF control */
+#define AGC_ON          0x04   /* AGC Enable */
+#define AWB_ON          0x02   /* AWB Enable */
+#define AEC_ON          0x01   /* AEC Enable */
+
+/* COM9 */
+#define BASE_AECAGC     0x80   /* Histogram or average based AEC/AGC */
+                               /* Automatic gain ceiling - maximum AGC value */
+#define GAIN_2x         0x00   /*    000 :   2x */
+#define GAIN_4x         0x10   /*    001 :   4x */
+#define GAIN_8x         0x20   /*    010 :   8x */
+#define GAIN_16x        0x30   /*    011 :  16x */
+#define GAIN_32x        0x40   /*    100 :  32x */
+#define GAIN_64x        0x50   /* 101 :  64x */
+#define GAIN_128x       0x60   /* 110 : 128x */
+#define DROP_VSYNC      0x04   /* Drop VSYNC output of corrupt frame */
+#define DROP_HREF       0x02   /* Drop HREF  output of corrupt frame */
+
+/* COM11 */
+#define SGLF_ON_OFF     0x02   /* Single frame ON/OFF selection */
+#define SGLF_TRIG       0x01   /* Single frame transfer trigger */
+
+/* HREF */
+#define HREF_VSTART_SHIFT      6       /* VSTART LSB */
+#define HREF_HSTART_SHIFT      4       /* HSTART 2 LSBs */
+#define HREF_VSIZE_SHIFT       2       /* VSIZE LSB */
+#define HREF_HSIZE_SHIFT       0       /* HSIZE 2 LSBs */
+
+/* EXHCH */
+#define EXHCH_VSIZE_SHIFT      2       /* VOUTSIZE LSB */
+#define EXHCH_HSIZE_SHIFT      0       /* HOUTSIZE 2 LSBs */
+
+/* DSP_CTRL1 */
+#define FIFO_ON         0x80   /* FIFO enable/disable selection */
+#define UV_ON_OFF       0x40   /* UV adjust function ON/OFF selection */
+#define YUV444_2_422    0x20   /* YUV444 to 422 UV channel option selection */
+#define CLR_MTRX_ON_OFF 0x10   /* Color matrix ON/OFF selection */
+#define INTPLT_ON_OFF   0x08   /* Interpolation ON/OFF selection */
+#define GMM_ON_OFF      0x04   /* Gamma function ON/OFF selection */
+#define AUTO_BLK_ON_OFF 0x02   /* Black defect auto correction ON/OFF */
+#define AUTO_WHT_ON_OFF 0x01   /* White define auto correction ON/OFF */
+
+/* DSP_CTRL3 */
+#define UV_MASK         0x80   /* UV output sequence option */
+#define UV_ON           0x80   /*   ON */
+#define UV_OFF          0x00   /*   OFF */
+#define CBAR_MASK       0x20   /* DSP Color bar mask */
+#define CBAR_ON         0x20   /*   ON */
+#define CBAR_OFF        0x00   /*   OFF */
+
+/* DSP_CTRL4 */
+#define DSP_OFMT_YUV   0x00
+#define DSP_OFMT_RGB   0x00
+#define DSP_OFMT_RAW8  0x02
+#define DSP_OFMT_RAW10 0x03
+
+/* DSPAUTO (DSP Auto Function ON/OFF Control) */
+#define AWB_ACTRL       0x80 /* AWB auto threshold control */
+#define DENOISE_ACTRL   0x40 /* De-noise auto threshold control */
+#define EDGE_ACTRL      0x20 /* Edge enhancement auto strength control */
+#define UV_ACTRL        0x10 /* UV adjust auto slope control */
+#define SCAL0_ACTRL     0x08 /* Auto scaling factor control */
+#define SCAL1_2_ACTRL   0x04 /* Auto scaling factor control */
+
+#define OV772X_MAX_WIDTH       VGA_WIDTH
+#define OV772X_MAX_HEIGHT      VGA_HEIGHT
+
+/*
+ * ID
+ */
+#define OV7720  0x7720
+#define OV7725  0x7721
+#define VERSION(pid, ver) ((pid<<8)|(ver&0xFF))
+
+/*
+ * struct
+ */
+
+struct ov772x_color_format {
+       u32 code;
+       enum v4l2_colorspace colorspace;
+       u8 dsp3;
+       u8 dsp4;
+       u8 com3;
+       u8 com7;
+};
+
+struct ov772x_win_size {
+       char                     *name;
+       unsigned char             com7_bit;
+       struct v4l2_rect          rect;
+};
+
+struct ov772x_priv {
+       struct v4l2_subdev                subdev;
+       struct v4l2_ctrl_handler          hdl;
+       struct v4l2_clk                  *clk;
+       struct ov772x_camera_info        *info;
+       const struct ov772x_color_format *cfmt;
+       const struct ov772x_win_size     *win;
+       unsigned short                    flag_vflip:1;
+       unsigned short                    flag_hflip:1;
+       /* band_filter = COM8[5] ? 256 - BDBASE : 0 */
+       unsigned short                    band_filter;
+};
+
+/*
+ * supported color format list
+ */
+static const struct ov772x_color_format ov772x_cfmts[] = {
+       {
+               .code           = MEDIA_BUS_FMT_YUYV8_2X8,
+               .colorspace     = V4L2_COLORSPACE_JPEG,
+               .dsp3           = 0x0,
+               .dsp4           = DSP_OFMT_YUV,
+               .com3           = SWAP_YUV,
+               .com7           = OFMT_YUV,
+       },
+       {
+               .code           = MEDIA_BUS_FMT_YVYU8_2X8,
+               .colorspace     = V4L2_COLORSPACE_JPEG,
+               .dsp3           = UV_ON,
+               .dsp4           = DSP_OFMT_YUV,
+               .com3           = SWAP_YUV,
+               .com7           = OFMT_YUV,
+       },
+       {
+               .code           = MEDIA_BUS_FMT_UYVY8_2X8,
+               .colorspace     = V4L2_COLORSPACE_JPEG,
+               .dsp3           = 0x0,
+               .dsp4           = DSP_OFMT_YUV,
+               .com3           = 0x0,
+               .com7           = OFMT_YUV,
+       },
+       {
+               .code           = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE,
+               .colorspace     = V4L2_COLORSPACE_SRGB,
+               .dsp3           = 0x0,
+               .dsp4           = DSP_OFMT_YUV,
+               .com3           = SWAP_RGB,
+               .com7           = FMT_RGB555 | OFMT_RGB,
+       },
+       {
+               .code           = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE,
+               .colorspace     = V4L2_COLORSPACE_SRGB,
+               .dsp3           = 0x0,
+               .dsp4           = DSP_OFMT_YUV,
+               .com3           = 0x0,
+               .com7           = FMT_RGB555 | OFMT_RGB,
+       },
+       {
+               .code           = MEDIA_BUS_FMT_RGB565_2X8_LE,
+               .colorspace     = V4L2_COLORSPACE_SRGB,
+               .dsp3           = 0x0,
+               .dsp4           = DSP_OFMT_YUV,
+               .com3           = SWAP_RGB,
+               .com7           = FMT_RGB565 | OFMT_RGB,
+       },
+       {
+               .code           = MEDIA_BUS_FMT_RGB565_2X8_BE,
+               .colorspace     = V4L2_COLORSPACE_SRGB,
+               .dsp3           = 0x0,
+               .dsp4           = DSP_OFMT_YUV,
+               .com3           = 0x0,
+               .com7           = FMT_RGB565 | OFMT_RGB,
+       },
+       {
+               /* Setting DSP4 to DSP_OFMT_RAW8 still gives 10-bit output,
+                * regardless of the COM7 value. We can thus only support 10-bit
+                * Bayer until someone figures it out.
+                */
+               .code           = MEDIA_BUS_FMT_SBGGR10_1X10,
+               .colorspace     = V4L2_COLORSPACE_SRGB,
+               .dsp3           = 0x0,
+               .dsp4           = DSP_OFMT_RAW10,
+               .com3           = 0x0,
+               .com7           = SENSOR_RAW | OFMT_BRAW,
+       },
+};
+
+
+/*
+ * window size list
+ */
+
+static const struct ov772x_win_size ov772x_win_sizes[] = {
+       {
+               .name     = "VGA",
+               .com7_bit = SLCT_VGA,
+               .rect = {
+                       .left = 140,
+                       .top = 14,
+                       .width = VGA_WIDTH,
+                       .height = VGA_HEIGHT,
+               },
+       }, {
+               .name     = "QVGA",
+               .com7_bit = SLCT_QVGA,
+               .rect = {
+                       .left = 252,
+                       .top = 6,
+                       .width = QVGA_WIDTH,
+                       .height = QVGA_HEIGHT,
+               },
+       },
+};
+
+/*
+ * general function
+ */
+
+static struct ov772x_priv *to_ov772x(struct v4l2_subdev *sd)
+{
+       return container_of(sd, struct ov772x_priv, subdev);
+}
+
+static inline int ov772x_read(struct i2c_client *client, u8 addr)
+{
+       return i2c_smbus_read_byte_data(client, addr);
+}
+
+static inline int ov772x_write(struct i2c_client *client, u8 addr, u8 value)
+{
+       return i2c_smbus_write_byte_data(client, addr, value);
+}
+
+static int ov772x_mask_set(struct i2c_client *client, u8  command, u8  mask,
+                          u8  set)
+{
+       s32 val = ov772x_read(client, command);
+       if (val < 0)
+               return val;
+
+       val &= ~mask;
+       val |= set & mask;
+
+       return ov772x_write(client, command, val);
+}
+
+static int ov772x_reset(struct i2c_client *client)
+{
+       int ret;
+
+       ret = ov772x_write(client, COM7, SCCB_RESET);
+       if (ret < 0)
+               return ret;
+
+       msleep(1);
+
+       return ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE);
+}
+
+/*
+ * soc_camera_ops function
+ */
+
+static int ov772x_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct ov772x_priv *priv = to_ov772x(sd);
+
+       if (!enable) {
+               ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE);
+               return 0;
+       }
+
+       ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, 0);
+
+       dev_dbg(&client->dev, "format %d, win %s\n",
+               priv->cfmt->code, priv->win->name);
+
+       return 0;
+}
+
+static int ov772x_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct ov772x_priv *priv = container_of(ctrl->handler,
+                                               struct ov772x_priv, hdl);
+       struct v4l2_subdev *sd = &priv->subdev;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret = 0;
+       u8 val;
+
+       switch (ctrl->id) {
+       case V4L2_CID_VFLIP:
+               val = ctrl->val ? VFLIP_IMG : 0x00;
+               priv->flag_vflip = ctrl->val;
+               if (priv->info->flags & OV772X_FLAG_VFLIP)
+                       val ^= VFLIP_IMG;
+               return ov772x_mask_set(client, COM3, VFLIP_IMG, val);
+       case V4L2_CID_HFLIP:
+               val = ctrl->val ? HFLIP_IMG : 0x00;
+               priv->flag_hflip = ctrl->val;
+               if (priv->info->flags & OV772X_FLAG_HFLIP)
+                       val ^= HFLIP_IMG;
+               return ov772x_mask_set(client, COM3, HFLIP_IMG, val);
+       case V4L2_CID_BAND_STOP_FILTER:
+               if (!ctrl->val) {
+                       /* Switch the filter off, it is on now */
+                       ret = ov772x_mask_set(client, BDBASE, 0xff, 0xff);
+                       if (!ret)
+                               ret = ov772x_mask_set(client, COM8,
+                                                     BNDF_ON_OFF, 0);
+               } else {
+                       /* Switch the filter on, set AEC low limit */
+                       val = 256 - ctrl->val;
+                       ret = ov772x_mask_set(client, COM8,
+                                             BNDF_ON_OFF, BNDF_ON_OFF);
+                       if (!ret)
+                               ret = ov772x_mask_set(client, BDBASE,
+                                                     0xff, val);
+               }
+               if (!ret)
+                       priv->band_filter = ctrl->val;
+               return ret;
+       }
+
+       return -EINVAL;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ov772x_g_register(struct v4l2_subdev *sd,
+                            struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret;
+
+       reg->size = 1;
+       if (reg->reg > 0xff)
+               return -EINVAL;
+
+       ret = ov772x_read(client, reg->reg);
+       if (ret < 0)
+               return ret;
+
+       reg->val = (__u64)ret;
+
+       return 0;
+}
+
+static int ov772x_s_register(struct v4l2_subdev *sd,
+                            const struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (reg->reg > 0xff ||
+           reg->val > 0xff)
+               return -EINVAL;
+
+       return ov772x_write(client, reg->reg, reg->val);
+}
+#endif
+
+static int ov772x_s_power(struct v4l2_subdev *sd, int on)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct ov772x_priv *priv = to_ov772x(sd);
+
+       return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
+}
+
+static const struct ov772x_win_size *ov772x_select_win(u32 width, u32 height)
+{
+       const struct ov772x_win_size *win = &ov772x_win_sizes[0];
+       u32 best_diff = UINT_MAX;
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(ov772x_win_sizes); ++i) {
+               u32 diff = abs(width - ov772x_win_sizes[i].rect.width)
+                        + abs(height - ov772x_win_sizes[i].rect.height);
+               if (diff < best_diff) {
+                       best_diff = diff;
+                       win = &ov772x_win_sizes[i];
+               }
+       }
+
+       return win;
+}
+
+static void ov772x_select_params(const struct v4l2_mbus_framefmt *mf,
+                                const struct ov772x_color_format **cfmt,
+                                const struct ov772x_win_size **win)
+{
+       unsigned int i;
+
+       /* Select a format. */
+       *cfmt = &ov772x_cfmts[0];
+
+       for (i = 0; i < ARRAY_SIZE(ov772x_cfmts); i++) {
+               if (mf->code == ov772x_cfmts[i].code) {
+                       *cfmt = &ov772x_cfmts[i];
+                       break;
+               }
+       }
+
+       /* Select a window size. */
+       *win = ov772x_select_win(mf->width, mf->height);
+}
+
+static int ov772x_set_params(struct ov772x_priv *priv,
+                            const struct ov772x_color_format *cfmt,
+                            const struct ov772x_win_size *win)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev);
+       int ret;
+       u8  val;
+
+       /*
+        * reset hardware
+        */
+       ov772x_reset(client);
+
+       /*
+        * Edge Ctrl
+        */
+       if (priv->info->edgectrl.strength & OV772X_MANUAL_EDGE_CTRL) {
+
+               /*
+                * Manual Edge Control Mode
+                *
+                * Edge auto strength bit is set by default.
+                * Remove it when manual mode.
+                */
+
+               ret = ov772x_mask_set(client, DSPAUTO, EDGE_ACTRL, 0x00);
+               if (ret < 0)
+                       goto ov772x_set_fmt_error;
+
+               ret = ov772x_mask_set(client,
+                                     EDGE_TRSHLD, OV772X_EDGE_THRESHOLD_MASK,
+                                     priv->info->edgectrl.threshold);
+               if (ret < 0)
+                       goto ov772x_set_fmt_error;
+
+               ret = ov772x_mask_set(client,
+                                     EDGE_STRNGT, OV772X_EDGE_STRENGTH_MASK,
+                                     priv->info->edgectrl.strength);
+               if (ret < 0)
+                       goto ov772x_set_fmt_error;
+
+       } else if (priv->info->edgectrl.upper > priv->info->edgectrl.lower) {
+               /*
+                * Auto Edge Control Mode
+                *
+                * set upper and lower limit
+                */
+               ret = ov772x_mask_set(client,
+                                     EDGE_UPPER, OV772X_EDGE_UPPER_MASK,
+                                     priv->info->edgectrl.upper);
+               if (ret < 0)
+                       goto ov772x_set_fmt_error;
+
+               ret = ov772x_mask_set(client,
+                                     EDGE_LOWER, OV772X_EDGE_LOWER_MASK,
+                                     priv->info->edgectrl.lower);
+               if (ret < 0)
+                       goto ov772x_set_fmt_error;
+       }
+
+       /* Format and window size */
+       ret = ov772x_write(client, HSTART, win->rect.left >> 2);
+       if (ret < 0)
+               goto ov772x_set_fmt_error;
+       ret = ov772x_write(client, HSIZE, win->rect.width >> 2);
+       if (ret < 0)
+               goto ov772x_set_fmt_error;
+       ret = ov772x_write(client, VSTART, win->rect.top >> 1);
+       if (ret < 0)
+               goto ov772x_set_fmt_error;
+       ret = ov772x_write(client, VSIZE, win->rect.height >> 1);
+       if (ret < 0)
+               goto ov772x_set_fmt_error;
+       ret = ov772x_write(client, HOUTSIZE, win->rect.width >> 2);
+       if (ret < 0)
+               goto ov772x_set_fmt_error;
+       ret = ov772x_write(client, VOUTSIZE, win->rect.height >> 1);
+       if (ret < 0)
+               goto ov772x_set_fmt_error;
+       ret = ov772x_write(client, HREF,
+                          ((win->rect.top & 1) << HREF_VSTART_SHIFT) |
+                          ((win->rect.left & 3) << HREF_HSTART_SHIFT) |
+                          ((win->rect.height & 1) << HREF_VSIZE_SHIFT) |
+                          ((win->rect.width & 3) << HREF_HSIZE_SHIFT));
+       if (ret < 0)
+               goto ov772x_set_fmt_error;
+       ret = ov772x_write(client, EXHCH,
+                          ((win->rect.height & 1) << EXHCH_VSIZE_SHIFT) |
+                          ((win->rect.width & 3) << EXHCH_HSIZE_SHIFT));
+       if (ret < 0)
+               goto ov772x_set_fmt_error;
+
+       /*
+        * set DSP_CTRL3
+        */
+       val = cfmt->dsp3;
+       if (val) {
+               ret = ov772x_mask_set(client,
+                                     DSP_CTRL3, UV_MASK, val);
+               if (ret < 0)
+                       goto ov772x_set_fmt_error;
+       }
+
+       /* DSP_CTRL4: AEC reference point and DSP output format. */
+       if (cfmt->dsp4) {
+               ret = ov772x_write(client, DSP_CTRL4, cfmt->dsp4);
+               if (ret < 0)
+                       goto ov772x_set_fmt_error;
+       }
+
+       /*
+        * set COM3
+        */
+       val = cfmt->com3;
+       if (priv->info->flags & OV772X_FLAG_VFLIP)
+               val |= VFLIP_IMG;
+       if (priv->info->flags & OV772X_FLAG_HFLIP)
+               val |= HFLIP_IMG;
+       if (priv->flag_vflip)
+               val ^= VFLIP_IMG;
+       if (priv->flag_hflip)
+               val ^= HFLIP_IMG;
+
+       ret = ov772x_mask_set(client,
+                             COM3, SWAP_MASK | IMG_MASK, val);
+       if (ret < 0)
+               goto ov772x_set_fmt_error;
+
+       /* COM7: Sensor resolution and output format control. */
+       ret = ov772x_write(client, COM7, win->com7_bit | cfmt->com7);
+       if (ret < 0)
+               goto ov772x_set_fmt_error;
+
+       /*
+        * set COM8
+        */
+       if (priv->band_filter) {
+               ret = ov772x_mask_set(client, COM8, BNDF_ON_OFF, BNDF_ON_OFF);
+               if (!ret)
+                       ret = ov772x_mask_set(client, BDBASE,
+                                             0xff, 256 - priv->band_filter);
+               if (ret < 0)
+                       goto ov772x_set_fmt_error;
+       }
+
+       return ret;
+
+ov772x_set_fmt_error:
+
+       ov772x_reset(client);
+
+       return ret;
+}
+
+static int ov772x_get_selection(struct v4l2_subdev *sd,
+               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_selection *sel)
+{
+       if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+               return -EINVAL;
+
+       sel->r.left = 0;
+       sel->r.top = 0;
+       switch (sel->target) {
+       case V4L2_SEL_TGT_CROP_BOUNDS:
+               sel->r.width = OV772X_MAX_WIDTH;
+               sel->r.height = OV772X_MAX_HEIGHT;
+               return 0;
+       case V4L2_SEL_TGT_CROP:
+               sel->r.width = VGA_WIDTH;
+               sel->r.height = VGA_HEIGHT;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int ov772x_get_fmt(struct v4l2_subdev *sd,
+               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_format *format)
+{
+       struct v4l2_mbus_framefmt *mf = &format->format;
+       struct ov772x_priv *priv = to_ov772x(sd);
+
+       if (format->pad)
+               return -EINVAL;
+
+       mf->width       = priv->win->rect.width;
+       mf->height      = priv->win->rect.height;
+       mf->code        = priv->cfmt->code;
+       mf->colorspace  = priv->cfmt->colorspace;
+       mf->field       = V4L2_FIELD_NONE;
+
+       return 0;
+}
+
+static int ov772x_set_fmt(struct v4l2_subdev *sd,
+               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_format *format)
+{
+       struct ov772x_priv *priv = to_ov772x(sd);
+       struct v4l2_mbus_framefmt *mf = &format->format;
+       const struct ov772x_color_format *cfmt;
+       const struct ov772x_win_size *win;
+       int ret;
+
+       if (format->pad)
+               return -EINVAL;
+
+       ov772x_select_params(mf, &cfmt, &win);
+
+       mf->code = cfmt->code;
+       mf->width = win->rect.width;
+       mf->height = win->rect.height;
+       mf->field = V4L2_FIELD_NONE;
+       mf->colorspace = cfmt->colorspace;
+
+       if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+               cfg->try_fmt = *mf;
+               return 0;
+       }
+
+       ret = ov772x_set_params(priv, cfmt, win);
+       if (ret < 0)
+               return ret;
+
+       priv->win = win;
+       priv->cfmt = cfmt;
+       return 0;
+}
+
+static int ov772x_video_probe(struct ov772x_priv *priv)
+{
+       struct i2c_client  *client = v4l2_get_subdevdata(&priv->subdev);
+       u8                  pid, ver;
+       const char         *devname;
+       int                 ret;
+
+       ret = ov772x_s_power(&priv->subdev, 1);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * check and show product ID and manufacturer ID
+        */
+       pid = ov772x_read(client, PID);
+       ver = ov772x_read(client, VER);
+
+       switch (VERSION(pid, ver)) {
+       case OV7720:
+               devname     = "ov7720";
+               break;
+       case OV7725:
+               devname     = "ov7725";
+               break;
+       default:
+               dev_err(&client->dev,
+                       "Product ID error %x:%x\n", pid, ver);
+               ret = -ENODEV;
+               goto done;
+       }
+
+       dev_info(&client->dev,
+                "%s Product ID %0x:%0x Manufacturer ID %x:%x\n",
+                devname,
+                pid,
+                ver,
+                ov772x_read(client, MIDH),
+                ov772x_read(client, MIDL));
+       ret = v4l2_ctrl_handler_setup(&priv->hdl);
+
+done:
+       ov772x_s_power(&priv->subdev, 0);
+       return ret;
+}
+
+static const struct v4l2_ctrl_ops ov772x_ctrl_ops = {
+       .s_ctrl = ov772x_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops ov772x_subdev_core_ops = {
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .g_register     = ov772x_g_register,
+       .s_register     = ov772x_s_register,
+#endif
+       .s_power        = ov772x_s_power,
+};
+
+static int ov772x_enum_mbus_code(struct v4l2_subdev *sd,
+               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_mbus_code_enum *code)
+{
+       if (code->pad || code->index >= ARRAY_SIZE(ov772x_cfmts))
+               return -EINVAL;
+
+       code->code = ov772x_cfmts[code->index].code;
+       return 0;
+}
+
+static int ov772x_g_mbus_config(struct v4l2_subdev *sd,
+                               struct v4l2_mbus_config *cfg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+
+       cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
+               V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
+               V4L2_MBUS_DATA_ACTIVE_HIGH;
+       cfg->type = V4L2_MBUS_PARALLEL;
+       cfg->flags = soc_camera_apply_board_flags(ssdd, cfg);
+
+       return 0;
+}
+
+static const struct v4l2_subdev_video_ops ov772x_subdev_video_ops = {
+       .s_stream       = ov772x_s_stream,
+       .g_mbus_config  = ov772x_g_mbus_config,
+};
+
+static const struct v4l2_subdev_pad_ops ov772x_subdev_pad_ops = {
+       .enum_mbus_code = ov772x_enum_mbus_code,
+       .get_selection  = ov772x_get_selection,
+       .get_fmt        = ov772x_get_fmt,
+       .set_fmt        = ov772x_set_fmt,
+};
+
+static const struct v4l2_subdev_ops ov772x_subdev_ops = {
+       .core   = &ov772x_subdev_core_ops,
+       .video  = &ov772x_subdev_video_ops,
+       .pad    = &ov772x_subdev_pad_ops,
+};
+
+/*
+ * i2c_driver function
+ */
+
+static int ov772x_probe(struct i2c_client *client,
+                       const struct i2c_device_id *did)
+{
+       struct ov772x_priv      *priv;
+       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct i2c_adapter      *adapter = to_i2c_adapter(client->dev.parent);
+       int                     ret;
+
+       if (!ssdd || !ssdd->drv_priv) {
+               dev_err(&client->dev, "OV772X: missing platform data!\n");
+               return -EINVAL;
+       }
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
+                                             I2C_FUNC_PROTOCOL_MANGLING)) {
+               dev_err(&adapter->dev,
+                       "I2C-Adapter doesn't support SMBUS_BYTE_DATA or PROTOCOL_MANGLING\n");
+               return -EIO;
+       }
+       client->flags |= I2C_CLIENT_SCCB;
+
+       priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->info = ssdd->drv_priv;
+
+       v4l2_i2c_subdev_init(&priv->subdev, client, &ov772x_subdev_ops);
+       v4l2_ctrl_handler_init(&priv->hdl, 3);
+       v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops,
+                       V4L2_CID_VFLIP, 0, 1, 1, 0);
+       v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops,
+                       V4L2_CID_HFLIP, 0, 1, 1, 0);
+       v4l2_ctrl_new_std(&priv->hdl, &ov772x_ctrl_ops,
+                       V4L2_CID_BAND_STOP_FILTER, 0, 256, 1, 0);
+       priv->subdev.ctrl_handler = &priv->hdl;
+       if (priv->hdl.error)
+               return priv->hdl.error;
+
+       priv->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(priv->clk)) {
+               ret = PTR_ERR(priv->clk);
+               goto eclkget;
+       }
+
+       ret = ov772x_video_probe(priv);
+       if (ret < 0) {
+               v4l2_clk_put(priv->clk);
+eclkget:
+               v4l2_ctrl_handler_free(&priv->hdl);
+       } else {
+               priv->cfmt = &ov772x_cfmts[0];
+               priv->win = &ov772x_win_sizes[0];
+       }
+
+       return ret;
+}
+
+static int ov772x_remove(struct i2c_client *client)
+{
+       struct ov772x_priv *priv = to_ov772x(i2c_get_clientdata(client));
+
+       v4l2_clk_put(priv->clk);
+       v4l2_device_unregister_subdev(&priv->subdev);
+       v4l2_ctrl_handler_free(&priv->hdl);
+       return 0;
+}
+
+static const struct i2c_device_id ov772x_id[] = {
+       { "ov772x", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ov772x_id);
+
+static struct i2c_driver ov772x_i2c_driver = {
+       .driver = {
+               .name = "ov772x",
+       },
+       .probe    = ov772x_probe,
+       .remove   = ov772x_remove,
+       .id_table = ov772x_id,
+};
+
+module_i2c_driver(ov772x_i2c_driver);
+
+MODULE_DESCRIPTION("SoC Camera driver for ov772x");
+MODULE_AUTHOR("Kuninori Morimoto");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/soc_camera/soc_ov9640.c b/drivers/media/i2c/soc_camera/soc_ov9640.c
new file mode 100644 (file)
index 0000000..eb91b82
--- /dev/null
@@ -0,0 +1,738 @@
+/*
+ * OmniVision OV96xx Camera Driver
+ *
+ * Copyright (C) 2009 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * Based on ov772x camera driver:
+ *
+ * Copyright (C) 2008 Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * Based on ov7670 and soc_camera_platform driver,
+ *
+ * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
+ * Copyright (C) 2008 Magnus Damm
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/videodev2.h>
+
+#include <media/soc_camera.h>
+#include <media/v4l2-clk.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+
+#include "ov9640.h"
+
+#define to_ov9640_sensor(sd)   container_of(sd, struct ov9640_priv, subdev)
+
+/* default register setup */
+static const struct ov9640_reg ov9640_regs_dflt[] = {
+       { OV9640_COM5,  OV9640_COM5_SYSCLK | OV9640_COM5_LONGEXP },
+       { OV9640_COM6,  OV9640_COM6_OPT_BLC | OV9640_COM6_ADBLC_BIAS |
+                       OV9640_COM6_FMT_RST | OV9640_COM6_ADBLC_OPTEN },
+       { OV9640_PSHFT, OV9640_PSHFT_VAL(0x01) },
+       { OV9640_ACOM,  OV9640_ACOM_2X_ANALOG | OV9640_ACOM_RSVD },
+       { OV9640_TSLB,  OV9640_TSLB_YUYV_UYVY },
+       { OV9640_COM16, OV9640_COM16_RB_AVG },
+
+       /* Gamma curve P */
+       { 0x6c, 0x40 }, { 0x6d, 0x30 }, { 0x6e, 0x4b }, { 0x6f, 0x60 },
+       { 0x70, 0x70 }, { 0x71, 0x70 }, { 0x72, 0x70 }, { 0x73, 0x70 },
+       { 0x74, 0x60 }, { 0x75, 0x60 }, { 0x76, 0x50 }, { 0x77, 0x48 },
+       { 0x78, 0x3a }, { 0x79, 0x2e }, { 0x7a, 0x28 }, { 0x7b, 0x22 },
+
+       /* Gamma curve T */
+       { 0x7c, 0x04 }, { 0x7d, 0x07 }, { 0x7e, 0x10 }, { 0x7f, 0x28 },
+       { 0x80, 0x36 }, { 0x81, 0x44 }, { 0x82, 0x52 }, { 0x83, 0x60 },
+       { 0x84, 0x6c }, { 0x85, 0x78 }, { 0x86, 0x8c }, { 0x87, 0x9e },
+       { 0x88, 0xbb }, { 0x89, 0xd2 }, { 0x8a, 0xe6 },
+};
+
+/* Configurations
+ * NOTE: for YUV, alter the following registers:
+ *             COM12 |= OV9640_COM12_YUV_AVG
+ *
+ *      for RGB, alter the following registers:
+ *             COM7  |= OV9640_COM7_RGB
+ *             COM13 |= OV9640_COM13_RGB_AVG
+ *             COM15 |= proper RGB color encoding mode
+ */
+static const struct ov9640_reg ov9640_regs_qqcif[] = {
+       { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x0f) },
+       { OV9640_COM1,  OV9640_COM1_QQFMT | OV9640_COM1_HREF_2SKIP },
+       { OV9640_COM4,  OV9640_COM4_QQ_VP | OV9640_COM4_RSVD },
+       { OV9640_COM7,  OV9640_COM7_QCIF },
+       { OV9640_COM12, OV9640_COM12_RSVD },
+       { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
+       { OV9640_COM15, OV9640_COM15_OR_10F0 },
+};
+
+static const struct ov9640_reg ov9640_regs_qqvga[] = {
+       { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x07) },
+       { OV9640_COM1,  OV9640_COM1_QQFMT | OV9640_COM1_HREF_2SKIP },
+       { OV9640_COM4,  OV9640_COM4_QQ_VP | OV9640_COM4_RSVD },
+       { OV9640_COM7,  OV9640_COM7_QVGA },
+       { OV9640_COM12, OV9640_COM12_RSVD },
+       { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
+       { OV9640_COM15, OV9640_COM15_OR_10F0 },
+};
+
+static const struct ov9640_reg ov9640_regs_qcif[] = {
+       { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x07) },
+       { OV9640_COM4,  OV9640_COM4_QQ_VP | OV9640_COM4_RSVD },
+       { OV9640_COM7,  OV9640_COM7_QCIF },
+       { OV9640_COM12, OV9640_COM12_RSVD },
+       { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
+       { OV9640_COM15, OV9640_COM15_OR_10F0 },
+};
+
+static const struct ov9640_reg ov9640_regs_qvga[] = {
+       { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x03) },
+       { OV9640_COM4,  OV9640_COM4_QQ_VP | OV9640_COM4_RSVD },
+       { OV9640_COM7,  OV9640_COM7_QVGA },
+       { OV9640_COM12, OV9640_COM12_RSVD },
+       { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
+       { OV9640_COM15, OV9640_COM15_OR_10F0 },
+};
+
+static const struct ov9640_reg ov9640_regs_cif[] = {
+       { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x03) },
+       { OV9640_COM3,  OV9640_COM3_VP },
+       { OV9640_COM7,  OV9640_COM7_CIF },
+       { OV9640_COM12, OV9640_COM12_RSVD },
+       { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
+       { OV9640_COM15, OV9640_COM15_OR_10F0 },
+};
+
+static const struct ov9640_reg ov9640_regs_vga[] = {
+       { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x01) },
+       { OV9640_COM3,  OV9640_COM3_VP },
+       { OV9640_COM7,  OV9640_COM7_VGA },
+       { OV9640_COM12, OV9640_COM12_RSVD },
+       { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
+       { OV9640_COM15, OV9640_COM15_OR_10F0 },
+};
+
+static const struct ov9640_reg ov9640_regs_sxga[] = {
+       { OV9640_CLKRC, OV9640_CLKRC_DPLL_EN | OV9640_CLKRC_DIV(0x01) },
+       { OV9640_COM3,  OV9640_COM3_VP },
+       { OV9640_COM7,  0 },
+       { OV9640_COM12, OV9640_COM12_RSVD },
+       { OV9640_COM13, OV9640_COM13_GAMMA_RAW | OV9640_COM13_MATRIX_EN },
+       { OV9640_COM15, OV9640_COM15_OR_10F0 },
+};
+
+static const struct ov9640_reg ov9640_regs_yuv[] = {
+       { OV9640_MTX1,  0x58 },
+       { OV9640_MTX2,  0x48 },
+       { OV9640_MTX3,  0x10 },
+       { OV9640_MTX4,  0x28 },
+       { OV9640_MTX5,  0x48 },
+       { OV9640_MTX6,  0x70 },
+       { OV9640_MTX7,  0x40 },
+       { OV9640_MTX8,  0x40 },
+       { OV9640_MTX9,  0x40 },
+       { OV9640_MTXS,  0x0f },
+};
+
+static const struct ov9640_reg ov9640_regs_rgb[] = {
+       { OV9640_MTX1,  0x71 },
+       { OV9640_MTX2,  0x3e },
+       { OV9640_MTX3,  0x0c },
+       { OV9640_MTX4,  0x33 },
+       { OV9640_MTX5,  0x72 },
+       { OV9640_MTX6,  0x00 },
+       { OV9640_MTX7,  0x2b },
+       { OV9640_MTX8,  0x66 },
+       { OV9640_MTX9,  0xd2 },
+       { OV9640_MTXS,  0x65 },
+};
+
+static u32 ov9640_codes[] = {
+       MEDIA_BUS_FMT_UYVY8_2X8,
+       MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE,
+       MEDIA_BUS_FMT_RGB565_2X8_LE,
+};
+
+/* read a register */
+static int ov9640_reg_read(struct i2c_client *client, u8 reg, u8 *val)
+{
+       int ret;
+       u8 data = reg;
+       struct i2c_msg msg = {
+               .addr   = client->addr,
+               .flags  = 0,
+               .len    = 1,
+               .buf    = &data,
+       };
+
+       ret = i2c_transfer(client->adapter, &msg, 1);
+       if (ret < 0)
+               goto err;
+
+       msg.flags = I2C_M_RD;
+       ret = i2c_transfer(client->adapter, &msg, 1);
+       if (ret < 0)
+               goto err;
+
+       *val = data;
+       return 0;
+
+err:
+       dev_err(&client->dev, "Failed reading register 0x%02x!\n", reg);
+       return ret;
+}
+
+/* write a register */
+static int ov9640_reg_write(struct i2c_client *client, u8 reg, u8 val)
+{
+       int ret;
+       u8 _val;
+       unsigned char data[2] = { reg, val };
+       struct i2c_msg msg = {
+               .addr   = client->addr,
+               .flags  = 0,
+               .len    = 2,
+               .buf    = data,
+       };
+
+       ret = i2c_transfer(client->adapter, &msg, 1);
+       if (ret < 0) {
+               dev_err(&client->dev, "Failed writing register 0x%02x!\n", reg);
+               return ret;
+       }
+
+       /* we have to read the register back ... no idea why, maybe HW bug */
+       ret = ov9640_reg_read(client, reg, &_val);
+       if (ret)
+               dev_err(&client->dev,
+                       "Failed reading back register 0x%02x!\n", reg);
+
+       return 0;
+}
+
+
+/* Read a register, alter its bits, write it back */
+static int ov9640_reg_rmw(struct i2c_client *client, u8 reg, u8 set, u8 unset)
+{
+       u8 val;
+       int ret;
+
+       ret = ov9640_reg_read(client, reg, &val);
+       if (ret) {
+               dev_err(&client->dev,
+                       "[Read]-Modify-Write of register %02x failed!\n", reg);
+               return ret;
+       }
+
+       val |= set;
+       val &= ~unset;
+
+       ret = ov9640_reg_write(client, reg, val);
+       if (ret)
+               dev_err(&client->dev,
+                       "Read-Modify-[Write] of register %02x failed!\n", reg);
+
+       return ret;
+}
+
+/* Soft reset the camera. This has nothing to do with the RESET pin! */
+static int ov9640_reset(struct i2c_client *client)
+{
+       int ret;
+
+       ret = ov9640_reg_write(client, OV9640_COM7, OV9640_COM7_SCCB_RESET);
+       if (ret)
+               dev_err(&client->dev,
+                       "An error occurred while entering soft reset!\n");
+
+       return ret;
+}
+
+/* Start/Stop streaming from the device */
+static int ov9640_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       return 0;
+}
+
+/* Set status of additional camera capabilities */
+static int ov9640_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct ov9640_priv *priv = container_of(ctrl->handler, struct ov9640_priv, hdl);
+       struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev);
+
+       switch (ctrl->id) {
+       case V4L2_CID_VFLIP:
+               if (ctrl->val)
+                       return ov9640_reg_rmw(client, OV9640_MVFP,
+                                                       OV9640_MVFP_V, 0);
+               return ov9640_reg_rmw(client, OV9640_MVFP, 0, OV9640_MVFP_V);
+       case V4L2_CID_HFLIP:
+               if (ctrl->val)
+                       return ov9640_reg_rmw(client, OV9640_MVFP,
+                                                       OV9640_MVFP_H, 0);
+               return ov9640_reg_rmw(client, OV9640_MVFP, 0, OV9640_MVFP_H);
+       }
+       return -EINVAL;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ov9640_get_register(struct v4l2_subdev *sd,
+                               struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret;
+       u8 val;
+
+       if (reg->reg & ~0xff)
+               return -EINVAL;
+
+       reg->size = 1;
+
+       ret = ov9640_reg_read(client, reg->reg, &val);
+       if (ret)
+               return ret;
+
+       reg->val = (__u64)val;
+
+       return 0;
+}
+
+static int ov9640_set_register(struct v4l2_subdev *sd,
+                               const struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (reg->reg & ~0xff || reg->val & ~0xff)
+               return -EINVAL;
+
+       return ov9640_reg_write(client, reg->reg, reg->val);
+}
+#endif
+
+static int ov9640_s_power(struct v4l2_subdev *sd, int on)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct ov9640_priv *priv = to_ov9640_sensor(sd);
+
+       return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
+}
+
+/* select nearest higher resolution for capture */
+static void ov9640_res_roundup(u32 *width, u32 *height)
+{
+       int i;
+       enum { QQCIF, QQVGA, QCIF, QVGA, CIF, VGA, SXGA };
+       static const int res_x[] = { 88, 160, 176, 320, 352, 640, 1280 };
+       static const int res_y[] = { 72, 120, 144, 240, 288, 480, 960 };
+
+       for (i = 0; i < ARRAY_SIZE(res_x); i++) {
+               if (res_x[i] >= *width && res_y[i] >= *height) {
+                       *width = res_x[i];
+                       *height = res_y[i];
+                       return;
+               }
+       }
+
+       *width = res_x[SXGA];
+       *height = res_y[SXGA];
+}
+
+/* Prepare necessary register changes depending on color encoding */
+static void ov9640_alter_regs(u32 code,
+                             struct ov9640_reg_alt *alt)
+{
+       switch (code) {
+       default:
+       case MEDIA_BUS_FMT_UYVY8_2X8:
+               alt->com12      = OV9640_COM12_YUV_AVG;
+               alt->com13      = OV9640_COM13_Y_DELAY_EN |
+                                       OV9640_COM13_YUV_DLY(0x01);
+               break;
+       case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE:
+               alt->com7       = OV9640_COM7_RGB;
+               alt->com13      = OV9640_COM13_RGB_AVG;
+               alt->com15      = OV9640_COM15_RGB_555;
+               break;
+       case MEDIA_BUS_FMT_RGB565_2X8_LE:
+               alt->com7       = OV9640_COM7_RGB;
+               alt->com13      = OV9640_COM13_RGB_AVG;
+               alt->com15      = OV9640_COM15_RGB_565;
+               break;
+       }
+}
+
+/* Setup registers according to resolution and color encoding */
+static int ov9640_write_regs(struct i2c_client *client, u32 width,
+               u32 code, struct ov9640_reg_alt *alts)
+{
+       const struct ov9640_reg *ov9640_regs, *matrix_regs;
+       int                     ov9640_regs_len, matrix_regs_len;
+       int                     i, ret;
+       u8                      val;
+
+       /* select register configuration for given resolution */
+       switch (width) {
+       case W_QQCIF:
+               ov9640_regs     = ov9640_regs_qqcif;
+               ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qqcif);
+               break;
+       case W_QQVGA:
+               ov9640_regs     = ov9640_regs_qqvga;
+               ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qqvga);
+               break;
+       case W_QCIF:
+               ov9640_regs     = ov9640_regs_qcif;
+               ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qcif);
+               break;
+       case W_QVGA:
+               ov9640_regs     = ov9640_regs_qvga;
+               ov9640_regs_len = ARRAY_SIZE(ov9640_regs_qvga);
+               break;
+       case W_CIF:
+               ov9640_regs     = ov9640_regs_cif;
+               ov9640_regs_len = ARRAY_SIZE(ov9640_regs_cif);
+               break;
+       case W_VGA:
+               ov9640_regs     = ov9640_regs_vga;
+               ov9640_regs_len = ARRAY_SIZE(ov9640_regs_vga);
+               break;
+       case W_SXGA:
+               ov9640_regs     = ov9640_regs_sxga;
+               ov9640_regs_len = ARRAY_SIZE(ov9640_regs_sxga);
+               break;
+       default:
+               dev_err(&client->dev, "Failed to select resolution!\n");
+               return -EINVAL;
+       }
+
+       /* select color matrix configuration for given color encoding */
+       if (code == MEDIA_BUS_FMT_UYVY8_2X8) {
+               matrix_regs     = ov9640_regs_yuv;
+               matrix_regs_len = ARRAY_SIZE(ov9640_regs_yuv);
+       } else {
+               matrix_regs     = ov9640_regs_rgb;
+               matrix_regs_len = ARRAY_SIZE(ov9640_regs_rgb);
+       }
+
+       /* write register settings into the module */
+       for (i = 0; i < ov9640_regs_len; i++) {
+               val = ov9640_regs[i].val;
+
+               switch (ov9640_regs[i].reg) {
+               case OV9640_COM7:
+                       val |= alts->com7;
+                       break;
+               case OV9640_COM12:
+                       val |= alts->com12;
+                       break;
+               case OV9640_COM13:
+                       val |= alts->com13;
+                       break;
+               case OV9640_COM15:
+                       val |= alts->com15;
+                       break;
+               }
+
+               ret = ov9640_reg_write(client, ov9640_regs[i].reg, val);
+               if (ret)
+                       return ret;
+       }
+
+       /* write color matrix configuration into the module */
+       for (i = 0; i < matrix_regs_len; i++) {
+               ret = ov9640_reg_write(client, matrix_regs[i].reg,
+                                               matrix_regs[i].val);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+/* program default register values */
+static int ov9640_prog_dflt(struct i2c_client *client)
+{
+       int i, ret;
+
+       for (i = 0; i < ARRAY_SIZE(ov9640_regs_dflt); i++) {
+               ret = ov9640_reg_write(client, ov9640_regs_dflt[i].reg,
+                                               ov9640_regs_dflt[i].val);
+               if (ret)
+                       return ret;
+       }
+
+       /* wait for the changes to actually happen, 140ms are not enough yet */
+       mdelay(150);
+
+       return 0;
+}
+
+/* set the format we will capture in */
+static int ov9640_s_fmt(struct v4l2_subdev *sd,
+                       struct v4l2_mbus_framefmt *mf)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct ov9640_reg_alt alts = {0};
+       int ret;
+
+       ov9640_alter_regs(mf->code, &alts);
+
+       ov9640_reset(client);
+
+       ret = ov9640_prog_dflt(client);
+       if (ret)
+               return ret;
+
+       return ov9640_write_regs(client, mf->width, mf->code, &alts);
+}
+
+static int ov9640_set_fmt(struct v4l2_subdev *sd,
+               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_format *format)
+{
+       struct v4l2_mbus_framefmt *mf = &format->format;
+
+       if (format->pad)
+               return -EINVAL;
+
+       ov9640_res_roundup(&mf->width, &mf->height);
+
+       mf->field = V4L2_FIELD_NONE;
+
+       switch (mf->code) {
+       case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE:
+       case MEDIA_BUS_FMT_RGB565_2X8_LE:
+               mf->colorspace = V4L2_COLORSPACE_SRGB;
+               break;
+       default:
+               mf->code = MEDIA_BUS_FMT_UYVY8_2X8;
+               /* fall through */
+       case MEDIA_BUS_FMT_UYVY8_2X8:
+               mf->colorspace = V4L2_COLORSPACE_JPEG;
+               break;
+       }
+
+       if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+               return ov9640_s_fmt(sd, mf);
+
+       cfg->try_fmt = *mf;
+       return 0;
+}
+
+static int ov9640_enum_mbus_code(struct v4l2_subdev *sd,
+               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_mbus_code_enum *code)
+{
+       if (code->pad || code->index >= ARRAY_SIZE(ov9640_codes))
+               return -EINVAL;
+
+       code->code = ov9640_codes[code->index];
+       return 0;
+}
+
+static int ov9640_get_selection(struct v4l2_subdev *sd,
+               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_selection *sel)
+{
+       if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+               return -EINVAL;
+
+       sel->r.left = 0;
+       sel->r.top = 0;
+       switch (sel->target) {
+       case V4L2_SEL_TGT_CROP_BOUNDS:
+       case V4L2_SEL_TGT_CROP:
+               sel->r.width = W_SXGA;
+               sel->r.height = H_SXGA;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int ov9640_video_probe(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct ov9640_priv *priv = to_ov9640_sensor(sd);
+       u8              pid, ver, midh, midl;
+       const char      *devname;
+       int             ret;
+
+       ret = ov9640_s_power(&priv->subdev, 1);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * check and show product ID and manufacturer ID
+        */
+
+       ret = ov9640_reg_read(client, OV9640_PID, &pid);
+       if (!ret)
+               ret = ov9640_reg_read(client, OV9640_VER, &ver);
+       if (!ret)
+               ret = ov9640_reg_read(client, OV9640_MIDH, &midh);
+       if (!ret)
+               ret = ov9640_reg_read(client, OV9640_MIDL, &midl);
+       if (ret)
+               goto done;
+
+       switch (VERSION(pid, ver)) {
+       case OV9640_V2:
+               devname         = "ov9640";
+               priv->revision  = 2;
+               break;
+       case OV9640_V3:
+               devname         = "ov9640";
+               priv->revision  = 3;
+               break;
+       default:
+               dev_err(&client->dev, "Product ID error %x:%x\n", pid, ver);
+               ret = -ENODEV;
+               goto done;
+       }
+
+       dev_info(&client->dev, "%s Product ID %0x:%0x Manufacturer ID %x:%x\n",
+                devname, pid, ver, midh, midl);
+
+       ret = v4l2_ctrl_handler_setup(&priv->hdl);
+
+done:
+       ov9640_s_power(&priv->subdev, 0);
+       return ret;
+}
+
+static const struct v4l2_ctrl_ops ov9640_ctrl_ops = {
+       .s_ctrl = ov9640_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops ov9640_core_ops = {
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .g_register             = ov9640_get_register,
+       .s_register             = ov9640_set_register,
+#endif
+       .s_power                = ov9640_s_power,
+};
+
+/* Request bus settings on camera side */
+static int ov9640_g_mbus_config(struct v4l2_subdev *sd,
+                               struct v4l2_mbus_config *cfg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+
+       cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
+               V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
+               V4L2_MBUS_DATA_ACTIVE_HIGH;
+       cfg->type = V4L2_MBUS_PARALLEL;
+       cfg->flags = soc_camera_apply_board_flags(ssdd, cfg);
+
+       return 0;
+}
+
+static const struct v4l2_subdev_video_ops ov9640_video_ops = {
+       .s_stream       = ov9640_s_stream,
+       .g_mbus_config  = ov9640_g_mbus_config,
+};
+
+static const struct v4l2_subdev_pad_ops ov9640_pad_ops = {
+       .enum_mbus_code = ov9640_enum_mbus_code,
+       .get_selection  = ov9640_get_selection,
+       .set_fmt        = ov9640_set_fmt,
+};
+
+static const struct v4l2_subdev_ops ov9640_subdev_ops = {
+       .core   = &ov9640_core_ops,
+       .video  = &ov9640_video_ops,
+       .pad    = &ov9640_pad_ops,
+};
+
+/*
+ * i2c_driver function
+ */
+static int ov9640_probe(struct i2c_client *client,
+                       const struct i2c_device_id *did)
+{
+       struct ov9640_priv *priv;
+       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       int ret;
+
+       if (!ssdd) {
+               dev_err(&client->dev, "Missing platform_data for driver\n");
+               return -EINVAL;
+       }
+
+       priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       v4l2_i2c_subdev_init(&priv->subdev, client, &ov9640_subdev_ops);
+
+       v4l2_ctrl_handler_init(&priv->hdl, 2);
+       v4l2_ctrl_new_std(&priv->hdl, &ov9640_ctrl_ops,
+                       V4L2_CID_VFLIP, 0, 1, 1, 0);
+       v4l2_ctrl_new_std(&priv->hdl, &ov9640_ctrl_ops,
+                       V4L2_CID_HFLIP, 0, 1, 1, 0);
+       priv->subdev.ctrl_handler = &priv->hdl;
+       if (priv->hdl.error)
+               return priv->hdl.error;
+
+       priv->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(priv->clk)) {
+               ret = PTR_ERR(priv->clk);
+               goto eclkget;
+       }
+
+       ret = ov9640_video_probe(client);
+       if (ret) {
+               v4l2_clk_put(priv->clk);
+eclkget:
+               v4l2_ctrl_handler_free(&priv->hdl);
+       }
+
+       return ret;
+}
+
+static int ov9640_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct ov9640_priv *priv = to_ov9640_sensor(sd);
+
+       v4l2_clk_put(priv->clk);
+       v4l2_device_unregister_subdev(&priv->subdev);
+       v4l2_ctrl_handler_free(&priv->hdl);
+       return 0;
+}
+
+static const struct i2c_device_id ov9640_id[] = {
+       { "ov9640", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ov9640_id);
+
+static struct i2c_driver ov9640_i2c_driver = {
+       .driver = {
+               .name = "ov9640",
+       },
+       .probe    = ov9640_probe,
+       .remove   = ov9640_remove,
+       .id_table = ov9640_id,
+};
+
+module_i2c_driver(ov9640_i2c_driver);
+
+MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV96xx");
+MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/soc_camera/soc_ov9740.c b/drivers/media/i2c/soc_camera/soc_ov9740.c
new file mode 100644 (file)
index 0000000..a07d314
--- /dev/null
@@ -0,0 +1,996 @@
+/*
+ * OmniVision OV9740 Camera Driver
+ *
+ * Copyright (C) 2011 NVIDIA Corporation
+ *
+ * Based on ov9640 camera driver.
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/v4l2-mediabus.h>
+
+#include <media/soc_camera.h>
+#include <media/v4l2-clk.h>
+#include <media/v4l2-ctrls.h>
+
+#define to_ov9740(sd)          container_of(sd, struct ov9740_priv, subdev)
+
+/* General Status Registers */
+#define OV9740_MODEL_ID_HI             0x0000
+#define OV9740_MODEL_ID_LO             0x0001
+#define OV9740_REVISION_NUMBER         0x0002
+#define OV9740_MANUFACTURER_ID         0x0003
+#define OV9740_SMIA_VERSION            0x0004
+
+/* General Setup Registers */
+#define OV9740_MODE_SELECT             0x0100
+#define OV9740_IMAGE_ORT               0x0101
+#define OV9740_SOFTWARE_RESET          0x0103
+#define OV9740_GRP_PARAM_HOLD          0x0104
+#define OV9740_MSK_CORRUP_FM           0x0105
+
+/* Timing Setting */
+#define OV9740_FRM_LENGTH_LN_HI                0x0340 /* VTS */
+#define OV9740_FRM_LENGTH_LN_LO                0x0341 /* VTS */
+#define OV9740_LN_LENGTH_PCK_HI                0x0342 /* HTS */
+#define OV9740_LN_LENGTH_PCK_LO                0x0343 /* HTS */
+#define OV9740_X_ADDR_START_HI         0x0344
+#define OV9740_X_ADDR_START_LO         0x0345
+#define OV9740_Y_ADDR_START_HI         0x0346
+#define OV9740_Y_ADDR_START_LO         0x0347
+#define OV9740_X_ADDR_END_HI           0x0348
+#define OV9740_X_ADDR_END_LO           0x0349
+#define OV9740_Y_ADDR_END_HI           0x034a
+#define OV9740_Y_ADDR_END_LO           0x034b
+#define OV9740_X_OUTPUT_SIZE_HI                0x034c
+#define OV9740_X_OUTPUT_SIZE_LO                0x034d
+#define OV9740_Y_OUTPUT_SIZE_HI                0x034e
+#define OV9740_Y_OUTPUT_SIZE_LO                0x034f
+
+/* IO Control Registers */
+#define OV9740_IO_CREL00               0x3002
+#define OV9740_IO_CREL01               0x3004
+#define OV9740_IO_CREL02               0x3005
+#define OV9740_IO_OUTPUT_SEL01         0x3026
+#define OV9740_IO_OUTPUT_SEL02         0x3027
+
+/* AWB Registers */
+#define OV9740_AWB_MANUAL_CTRL         0x3406
+
+/* Analog Control Registers */
+#define OV9740_ANALOG_CTRL01           0x3601
+#define OV9740_ANALOG_CTRL02           0x3602
+#define OV9740_ANALOG_CTRL03           0x3603
+#define OV9740_ANALOG_CTRL04           0x3604
+#define OV9740_ANALOG_CTRL10           0x3610
+#define OV9740_ANALOG_CTRL12           0x3612
+#define OV9740_ANALOG_CTRL15           0x3615
+#define OV9740_ANALOG_CTRL20           0x3620
+#define OV9740_ANALOG_CTRL21           0x3621
+#define OV9740_ANALOG_CTRL22           0x3622
+#define OV9740_ANALOG_CTRL30           0x3630
+#define OV9740_ANALOG_CTRL31           0x3631
+#define OV9740_ANALOG_CTRL32           0x3632
+#define OV9740_ANALOG_CTRL33           0x3633
+
+/* Sensor Control */
+#define OV9740_SENSOR_CTRL03           0x3703
+#define OV9740_SENSOR_CTRL04           0x3704
+#define OV9740_SENSOR_CTRL05           0x3705
+#define OV9740_SENSOR_CTRL07           0x3707
+
+/* Timing Control */
+#define OV9740_TIMING_CTRL17           0x3817
+#define OV9740_TIMING_CTRL19           0x3819
+#define OV9740_TIMING_CTRL33           0x3833
+#define OV9740_TIMING_CTRL35           0x3835
+
+/* Banding Filter */
+#define OV9740_AEC_MAXEXPO_60_H                0x3a02
+#define OV9740_AEC_MAXEXPO_60_L                0x3a03
+#define OV9740_AEC_B50_STEP_HI         0x3a08
+#define OV9740_AEC_B50_STEP_LO         0x3a09
+#define OV9740_AEC_B60_STEP_HI         0x3a0a
+#define OV9740_AEC_B60_STEP_LO         0x3a0b
+#define OV9740_AEC_CTRL0D              0x3a0d
+#define OV9740_AEC_CTRL0E              0x3a0e
+#define OV9740_AEC_MAXEXPO_50_H                0x3a14
+#define OV9740_AEC_MAXEXPO_50_L                0x3a15
+
+/* AEC/AGC Control */
+#define OV9740_AEC_ENABLE              0x3503
+#define OV9740_GAIN_CEILING_01         0x3a18
+#define OV9740_GAIN_CEILING_02         0x3a19
+#define OV9740_AEC_HI_THRESHOLD                0x3a11
+#define OV9740_AEC_3A1A                        0x3a1a
+#define OV9740_AEC_CTRL1B_WPT2         0x3a1b
+#define OV9740_AEC_CTRL0F_WPT          0x3a0f
+#define OV9740_AEC_CTRL10_BPT          0x3a10
+#define OV9740_AEC_CTRL1E_BPT2         0x3a1e
+#define OV9740_AEC_LO_THRESHOLD                0x3a1f
+
+/* BLC Control */
+#define OV9740_BLC_AUTO_ENABLE         0x4002
+#define OV9740_BLC_MODE                        0x4005
+
+/* VFIFO */
+#define OV9740_VFIFO_READ_START_HI     0x4608
+#define OV9740_VFIFO_READ_START_LO     0x4609
+
+/* DVP Control */
+#define OV9740_DVP_VSYNC_CTRL02                0x4702
+#define OV9740_DVP_VSYNC_MODE          0x4704
+#define OV9740_DVP_VSYNC_CTRL06                0x4706
+
+/* PLL Setting */
+#define OV9740_PLL_MODE_CTRL01         0x3104
+#define OV9740_PRE_PLL_CLK_DIV         0x0305
+#define OV9740_PLL_MULTIPLIER          0x0307
+#define OV9740_VT_SYS_CLK_DIV          0x0303
+#define OV9740_VT_PIX_CLK_DIV          0x0301
+#define OV9740_PLL_CTRL3010            0x3010
+#define OV9740_VFIFO_CTRL00            0x460e
+
+/* ISP Control */
+#define OV9740_ISP_CTRL00              0x5000
+#define OV9740_ISP_CTRL01              0x5001
+#define OV9740_ISP_CTRL03              0x5003
+#define OV9740_ISP_CTRL05              0x5005
+#define OV9740_ISP_CTRL12              0x5012
+#define OV9740_ISP_CTRL19              0x5019
+#define OV9740_ISP_CTRL1A              0x501a
+#define OV9740_ISP_CTRL1E              0x501e
+#define OV9740_ISP_CTRL1F              0x501f
+#define OV9740_ISP_CTRL20              0x5020
+#define OV9740_ISP_CTRL21              0x5021
+
+/* AWB */
+#define OV9740_AWB_CTRL00              0x5180
+#define OV9740_AWB_CTRL01              0x5181
+#define OV9740_AWB_CTRL02              0x5182
+#define OV9740_AWB_CTRL03              0x5183
+#define OV9740_AWB_ADV_CTRL01          0x5184
+#define OV9740_AWB_ADV_CTRL02          0x5185
+#define OV9740_AWB_ADV_CTRL03          0x5186
+#define OV9740_AWB_ADV_CTRL04          0x5187
+#define OV9740_AWB_ADV_CTRL05          0x5188
+#define OV9740_AWB_ADV_CTRL06          0x5189
+#define OV9740_AWB_ADV_CTRL07          0x518a
+#define OV9740_AWB_ADV_CTRL08          0x518b
+#define OV9740_AWB_ADV_CTRL09          0x518c
+#define OV9740_AWB_ADV_CTRL10          0x518d
+#define OV9740_AWB_ADV_CTRL11          0x518e
+#define OV9740_AWB_CTRL0F              0x518f
+#define OV9740_AWB_CTRL10              0x5190
+#define OV9740_AWB_CTRL11              0x5191
+#define OV9740_AWB_CTRL12              0x5192
+#define OV9740_AWB_CTRL13              0x5193
+#define OV9740_AWB_CTRL14              0x5194
+
+/* MIPI Control */
+#define OV9740_MIPI_CTRL00             0x4800
+#define OV9740_MIPI_3837               0x3837
+#define OV9740_MIPI_CTRL01             0x4801
+#define OV9740_MIPI_CTRL03             0x4803
+#define OV9740_MIPI_CTRL05             0x4805
+#define OV9740_VFIFO_RD_CTRL           0x4601
+#define OV9740_MIPI_CTRL_3012          0x3012
+#define OV9740_SC_CMMM_MIPI_CTR                0x3014
+
+#define OV9740_MAX_WIDTH               1280
+#define OV9740_MAX_HEIGHT              720
+
+/* Misc. structures */
+struct ov9740_reg {
+       u16                             reg;
+       u8                              val;
+};
+
+struct ov9740_priv {
+       struct v4l2_subdev              subdev;
+       struct v4l2_ctrl_handler        hdl;
+       struct v4l2_clk                 *clk;
+
+       u16                             model;
+       u8                              revision;
+       u8                              manid;
+       u8                              smiaver;
+
+       bool                            flag_vflip;
+       bool                            flag_hflip;
+
+       /* For suspend/resume. */
+       struct v4l2_mbus_framefmt       current_mf;
+       bool                            current_enable;
+};
+
+static const struct ov9740_reg ov9740_defaults[] = {
+       /* Software Reset */
+       { OV9740_SOFTWARE_RESET,        0x01 },
+
+       /* Banding Filter */
+       { OV9740_AEC_B50_STEP_HI,       0x00 },
+       { OV9740_AEC_B50_STEP_LO,       0xe8 },
+       { OV9740_AEC_CTRL0E,            0x03 },
+       { OV9740_AEC_MAXEXPO_50_H,      0x15 },
+       { OV9740_AEC_MAXEXPO_50_L,      0xc6 },
+       { OV9740_AEC_B60_STEP_HI,       0x00 },
+       { OV9740_AEC_B60_STEP_LO,       0xc0 },
+       { OV9740_AEC_CTRL0D,            0x04 },
+       { OV9740_AEC_MAXEXPO_60_H,      0x18 },
+       { OV9740_AEC_MAXEXPO_60_L,      0x20 },
+
+       /* LC */
+       { 0x5842, 0x02 }, { 0x5843, 0x5e }, { 0x5844, 0x04 }, { 0x5845, 0x32 },
+       { 0x5846, 0x03 }, { 0x5847, 0x29 }, { 0x5848, 0x02 }, { 0x5849, 0xcc },
+
+       /* Un-documented OV9740 registers */
+       { 0x5800, 0x29 }, { 0x5801, 0x25 }, { 0x5802, 0x20 }, { 0x5803, 0x21 },
+       { 0x5804, 0x26 }, { 0x5805, 0x2e }, { 0x5806, 0x11 }, { 0x5807, 0x0c },
+       { 0x5808, 0x09 }, { 0x5809, 0x0a }, { 0x580a, 0x0e }, { 0x580b, 0x16 },
+       { 0x580c, 0x06 }, { 0x580d, 0x02 }, { 0x580e, 0x00 }, { 0x580f, 0x00 },
+       { 0x5810, 0x04 }, { 0x5811, 0x0a }, { 0x5812, 0x05 }, { 0x5813, 0x02 },
+       { 0x5814, 0x00 }, { 0x5815, 0x00 }, { 0x5816, 0x03 }, { 0x5817, 0x09 },
+       { 0x5818, 0x0f }, { 0x5819, 0x0a }, { 0x581a, 0x07 }, { 0x581b, 0x08 },
+       { 0x581c, 0x0b }, { 0x581d, 0x14 }, { 0x581e, 0x28 }, { 0x581f, 0x23 },
+       { 0x5820, 0x1d }, { 0x5821, 0x1e }, { 0x5822, 0x24 }, { 0x5823, 0x2a },
+       { 0x5824, 0x4f }, { 0x5825, 0x6f }, { 0x5826, 0x5f }, { 0x5827, 0x7f },
+       { 0x5828, 0x9f }, { 0x5829, 0x5f }, { 0x582a, 0x8f }, { 0x582b, 0x9e },
+       { 0x582c, 0x8f }, { 0x582d, 0x9f }, { 0x582e, 0x4f }, { 0x582f, 0x87 },
+       { 0x5830, 0x86 }, { 0x5831, 0x97 }, { 0x5832, 0xae }, { 0x5833, 0x3f },
+       { 0x5834, 0x8e }, { 0x5835, 0x7c }, { 0x5836, 0x7e }, { 0x5837, 0xaf },
+       { 0x5838, 0x8f }, { 0x5839, 0x8f }, { 0x583a, 0x9f }, { 0x583b, 0x7f },
+       { 0x583c, 0x5f },
+
+       /* Y Gamma */
+       { 0x5480, 0x07 }, { 0x5481, 0x18 }, { 0x5482, 0x2c }, { 0x5483, 0x4e },
+       { 0x5484, 0x5e }, { 0x5485, 0x6b }, { 0x5486, 0x77 }, { 0x5487, 0x82 },
+       { 0x5488, 0x8c }, { 0x5489, 0x95 }, { 0x548a, 0xa4 }, { 0x548b, 0xb1 },
+       { 0x548c, 0xc6 }, { 0x548d, 0xd8 }, { 0x548e, 0xe9 },
+
+       /* UV Gamma */
+       { 0x5490, 0x0f }, { 0x5491, 0xff }, { 0x5492, 0x0d }, { 0x5493, 0x05 },
+       { 0x5494, 0x07 }, { 0x5495, 0x1a }, { 0x5496, 0x04 }, { 0x5497, 0x01 },
+       { 0x5498, 0x03 }, { 0x5499, 0x53 }, { 0x549a, 0x02 }, { 0x549b, 0xeb },
+       { 0x549c, 0x02 }, { 0x549d, 0xa0 }, { 0x549e, 0x02 }, { 0x549f, 0x67 },
+       { 0x54a0, 0x02 }, { 0x54a1, 0x3b }, { 0x54a2, 0x02 }, { 0x54a3, 0x18 },
+       { 0x54a4, 0x01 }, { 0x54a5, 0xe7 }, { 0x54a6, 0x01 }, { 0x54a7, 0xc3 },
+       { 0x54a8, 0x01 }, { 0x54a9, 0x94 }, { 0x54aa, 0x01 }, { 0x54ab, 0x72 },
+       { 0x54ac, 0x01 }, { 0x54ad, 0x57 },
+
+       /* AWB */
+       { OV9740_AWB_CTRL00,            0xf0 },
+       { OV9740_AWB_CTRL01,            0x00 },
+       { OV9740_AWB_CTRL02,            0x41 },
+       { OV9740_AWB_CTRL03,            0x42 },
+       { OV9740_AWB_ADV_CTRL01,        0x8a },
+       { OV9740_AWB_ADV_CTRL02,        0x61 },
+       { OV9740_AWB_ADV_CTRL03,        0xce },
+       { OV9740_AWB_ADV_CTRL04,        0xa8 },
+       { OV9740_AWB_ADV_CTRL05,        0x17 },
+       { OV9740_AWB_ADV_CTRL06,        0x1f },
+       { OV9740_AWB_ADV_CTRL07,        0x27 },
+       { OV9740_AWB_ADV_CTRL08,        0x41 },
+       { OV9740_AWB_ADV_CTRL09,        0x34 },
+       { OV9740_AWB_ADV_CTRL10,        0xf0 },
+       { OV9740_AWB_ADV_CTRL11,        0x10 },
+       { OV9740_AWB_CTRL0F,            0xff },
+       { OV9740_AWB_CTRL10,            0x00 },
+       { OV9740_AWB_CTRL11,            0xff },
+       { OV9740_AWB_CTRL12,            0x00 },
+       { OV9740_AWB_CTRL13,            0xff },
+       { OV9740_AWB_CTRL14,            0x00 },
+
+       /* CIP */
+       { 0x530d, 0x12 },
+
+       /* CMX */
+       { 0x5380, 0x01 }, { 0x5381, 0x00 }, { 0x5382, 0x00 }, { 0x5383, 0x17 },
+       { 0x5384, 0x00 }, { 0x5385, 0x01 }, { 0x5386, 0x00 }, { 0x5387, 0x00 },
+       { 0x5388, 0x00 }, { 0x5389, 0xe0 }, { 0x538a, 0x00 }, { 0x538b, 0x20 },
+       { 0x538c, 0x00 }, { 0x538d, 0x00 }, { 0x538e, 0x00 }, { 0x538f, 0x16 },
+       { 0x5390, 0x00 }, { 0x5391, 0x9c }, { 0x5392, 0x00 }, { 0x5393, 0xa0 },
+       { 0x5394, 0x18 },
+
+       /* 50/60 Detection */
+       { 0x3c0a, 0x9c }, { 0x3c0b, 0x3f },
+
+       /* Output Select */
+       { OV9740_IO_OUTPUT_SEL01,       0x00 },
+       { OV9740_IO_OUTPUT_SEL02,       0x00 },
+       { OV9740_IO_CREL00,             0x00 },
+       { OV9740_IO_CREL01,             0x00 },
+       { OV9740_IO_CREL02,             0x00 },
+
+       /* AWB Control */
+       { OV9740_AWB_MANUAL_CTRL,       0x00 },
+
+       /* Analog Control */
+       { OV9740_ANALOG_CTRL03,         0xaa },
+       { OV9740_ANALOG_CTRL32,         0x2f },
+       { OV9740_ANALOG_CTRL20,         0x66 },
+       { OV9740_ANALOG_CTRL21,         0xc0 },
+       { OV9740_ANALOG_CTRL31,         0x52 },
+       { OV9740_ANALOG_CTRL33,         0x50 },
+       { OV9740_ANALOG_CTRL30,         0xca },
+       { OV9740_ANALOG_CTRL04,         0x0c },
+       { OV9740_ANALOG_CTRL01,         0x40 },
+       { OV9740_ANALOG_CTRL02,         0x16 },
+       { OV9740_ANALOG_CTRL10,         0xa1 },
+       { OV9740_ANALOG_CTRL12,         0x24 },
+       { OV9740_ANALOG_CTRL22,         0x9f },
+       { OV9740_ANALOG_CTRL15,         0xf0 },
+
+       /* Sensor Control */
+       { OV9740_SENSOR_CTRL03,         0x42 },
+       { OV9740_SENSOR_CTRL04,         0x10 },
+       { OV9740_SENSOR_CTRL05,         0x45 },
+       { OV9740_SENSOR_CTRL07,         0x14 },
+
+       /* Timing Control */
+       { OV9740_TIMING_CTRL33,         0x04 },
+       { OV9740_TIMING_CTRL35,         0x02 },
+       { OV9740_TIMING_CTRL19,         0x6e },
+       { OV9740_TIMING_CTRL17,         0x94 },
+
+       /* AEC/AGC Control */
+       { OV9740_AEC_ENABLE,            0x10 },
+       { OV9740_GAIN_CEILING_01,       0x00 },
+       { OV9740_GAIN_CEILING_02,       0x7f },
+       { OV9740_AEC_HI_THRESHOLD,      0xa0 },
+       { OV9740_AEC_3A1A,              0x05 },
+       { OV9740_AEC_CTRL1B_WPT2,       0x50 },
+       { OV9740_AEC_CTRL0F_WPT,        0x50 },
+       { OV9740_AEC_CTRL10_BPT,        0x4c },
+       { OV9740_AEC_CTRL1E_BPT2,       0x4c },
+       { OV9740_AEC_LO_THRESHOLD,      0x26 },
+
+       /* BLC Control */
+       { OV9740_BLC_AUTO_ENABLE,       0x45 },
+       { OV9740_BLC_MODE,              0x18 },
+
+       /* DVP Control */
+       { OV9740_DVP_VSYNC_CTRL02,      0x04 },
+       { OV9740_DVP_VSYNC_MODE,        0x00 },
+       { OV9740_DVP_VSYNC_CTRL06,      0x08 },
+
+       /* PLL Setting */
+       { OV9740_PLL_MODE_CTRL01,       0x20 },
+       { OV9740_PRE_PLL_CLK_DIV,       0x03 },
+       { OV9740_PLL_MULTIPLIER,        0x4c },
+       { OV9740_VT_SYS_CLK_DIV,        0x01 },
+       { OV9740_VT_PIX_CLK_DIV,        0x08 },
+       { OV9740_PLL_CTRL3010,          0x01 },
+       { OV9740_VFIFO_CTRL00,          0x82 },
+
+       /* Timing Setting */
+       /* VTS */
+       { OV9740_FRM_LENGTH_LN_HI,      0x03 },
+       { OV9740_FRM_LENGTH_LN_LO,      0x07 },
+       /* HTS */
+       { OV9740_LN_LENGTH_PCK_HI,      0x06 },
+       { OV9740_LN_LENGTH_PCK_LO,      0x62 },
+
+       /* MIPI Control */
+       { OV9740_MIPI_CTRL00,           0x44 }, /* 0x64 for discontinuous clk */
+       { OV9740_MIPI_3837,             0x01 },
+       { OV9740_MIPI_CTRL01,           0x0f },
+       { OV9740_MIPI_CTRL03,           0x05 },
+       { OV9740_MIPI_CTRL05,           0x10 },
+       { OV9740_VFIFO_RD_CTRL,         0x16 },
+       { OV9740_MIPI_CTRL_3012,        0x70 },
+       { OV9740_SC_CMMM_MIPI_CTR,      0x01 },
+
+       /* YUYV order */
+       { OV9740_ISP_CTRL19,            0x02 },
+};
+
+static u32 ov9740_codes[] = {
+       MEDIA_BUS_FMT_YUYV8_2X8,
+};
+
+/* read a register */
+static int ov9740_reg_read(struct i2c_client *client, u16 reg, u8 *val)
+{
+       int ret;
+       struct i2c_msg msg[] = {
+               {
+                       .addr   = client->addr,
+                       .flags  = 0,
+                       .len    = 2,
+                       .buf    = (u8 *)&reg,
+               },
+               {
+                       .addr   = client->addr,
+                       .flags  = I2C_M_RD,
+                       .len    = 1,
+                       .buf    = val,
+               },
+       };
+
+       reg = swab16(reg);
+
+       ret = i2c_transfer(client->adapter, msg, 2);
+       if (ret < 0) {
+               dev_err(&client->dev, "Failed reading register 0x%04x!\n", reg);
+               return ret;
+       }
+
+       return 0;
+}
+
+/* write a register */
+static int ov9740_reg_write(struct i2c_client *client, u16 reg, u8 val)
+{
+       struct i2c_msg msg;
+       struct {
+               u16 reg;
+               u8 val;
+       } __packed buf;
+       int ret;
+
+       reg = swab16(reg);
+
+       buf.reg = reg;
+       buf.val = val;
+
+       msg.addr        = client->addr;
+       msg.flags       = 0;
+       msg.len         = 3;
+       msg.buf         = (u8 *)&buf;
+
+       ret = i2c_transfer(client->adapter, &msg, 1);
+       if (ret < 0) {
+               dev_err(&client->dev, "Failed writing register 0x%04x!\n", reg);
+               return ret;
+       }
+
+       return 0;
+}
+
+
+/* Read a register, alter its bits, write it back */
+static int ov9740_reg_rmw(struct i2c_client *client, u16 reg, u8 set, u8 unset)
+{
+       u8 val;
+       int ret;
+
+       ret = ov9740_reg_read(client, reg, &val);
+       if (ret < 0) {
+               dev_err(&client->dev,
+                       "[Read]-Modify-Write of register 0x%04x failed!\n",
+                       reg);
+               return ret;
+       }
+
+       val |= set;
+       val &= ~unset;
+
+       ret = ov9740_reg_write(client, reg, val);
+       if (ret < 0) {
+               dev_err(&client->dev,
+                       "Read-Modify-[Write] of register 0x%04x failed!\n",
+                       reg);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int ov9740_reg_write_array(struct i2c_client *client,
+                                 const struct ov9740_reg *regarray,
+                                 int regarraylen)
+{
+       int i;
+       int ret;
+
+       for (i = 0; i < regarraylen; i++) {
+               ret = ov9740_reg_write(client,
+                                      regarray[i].reg, regarray[i].val);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+/* Start/Stop streaming from the device */
+static int ov9740_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct ov9740_priv *priv = to_ov9740(sd);
+       int ret;
+
+       /* Program orientation register. */
+       if (priv->flag_vflip)
+               ret = ov9740_reg_rmw(client, OV9740_IMAGE_ORT, 0x2, 0);
+       else
+               ret = ov9740_reg_rmw(client, OV9740_IMAGE_ORT, 0, 0x2);
+       if (ret < 0)
+               return ret;
+
+       if (priv->flag_hflip)
+               ret = ov9740_reg_rmw(client, OV9740_IMAGE_ORT, 0x1, 0);
+       else
+               ret = ov9740_reg_rmw(client, OV9740_IMAGE_ORT, 0, 0x1);
+       if (ret < 0)
+               return ret;
+
+       if (enable) {
+               dev_dbg(&client->dev, "Enabling Streaming\n");
+               /* Start Streaming */
+               ret = ov9740_reg_write(client, OV9740_MODE_SELECT, 0x01);
+
+       } else {
+               dev_dbg(&client->dev, "Disabling Streaming\n");
+               /* Software Reset */
+               ret = ov9740_reg_write(client, OV9740_SOFTWARE_RESET, 0x01);
+               if (!ret)
+                       /* Setting Streaming to Standby */
+                       ret = ov9740_reg_write(client, OV9740_MODE_SELECT,
+                                              0x00);
+       }
+
+       priv->current_enable = enable;
+
+       return ret;
+}
+
+/* select nearest higher resolution for capture */
+static void ov9740_res_roundup(u32 *width, u32 *height)
+{
+       /* Width must be a multiple of 4 pixels. */
+       *width = ALIGN(*width, 4);
+
+       /* Max resolution is 1280x720 (720p). */
+       if (*width > OV9740_MAX_WIDTH)
+               *width = OV9740_MAX_WIDTH;
+
+       if (*height > OV9740_MAX_HEIGHT)
+               *height = OV9740_MAX_HEIGHT;
+}
+
+/* Setup registers according to resolution and color encoding */
+static int ov9740_set_res(struct i2c_client *client, u32 width, u32 height)
+{
+       u32 x_start;
+       u32 y_start;
+       u32 x_end;
+       u32 y_end;
+       bool scaling = false;
+       u32 scale_input_x;
+       u32 scale_input_y;
+       int ret;
+
+       if ((width != OV9740_MAX_WIDTH) || (height != OV9740_MAX_HEIGHT))
+               scaling = true;
+
+       /*
+        * Try to use as much of the sensor area as possible when supporting
+        * smaller resolutions.  Depending on the aspect ratio of the
+        * chosen resolution, we can either use the full width of the sensor,
+        * or the full height of the sensor (or both if the aspect ratio is
+        * the same as 1280x720.
+        */
+       if ((OV9740_MAX_WIDTH * height) > (OV9740_MAX_HEIGHT * width)) {
+               scale_input_x = (OV9740_MAX_HEIGHT * width) / height;
+               scale_input_y = OV9740_MAX_HEIGHT;
+       } else {
+               scale_input_x = OV9740_MAX_WIDTH;
+               scale_input_y = (OV9740_MAX_WIDTH * height) / width;
+       }
+
+       /* These describe the area of the sensor to use. */
+       x_start = (OV9740_MAX_WIDTH - scale_input_x) / 2;
+       y_start = (OV9740_MAX_HEIGHT - scale_input_y) / 2;
+       x_end = x_start + scale_input_x - 1;
+       y_end = y_start + scale_input_y - 1;
+
+       ret = ov9740_reg_write(client, OV9740_X_ADDR_START_HI, x_start >> 8);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_X_ADDR_START_LO, x_start & 0xff);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_Y_ADDR_START_HI, y_start >> 8);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_Y_ADDR_START_LO, y_start & 0xff);
+       if (ret)
+               goto done;
+
+       ret = ov9740_reg_write(client, OV9740_X_ADDR_END_HI, x_end >> 8);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_X_ADDR_END_LO, x_end & 0xff);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_Y_ADDR_END_HI, y_end >> 8);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_Y_ADDR_END_LO, y_end & 0xff);
+       if (ret)
+               goto done;
+
+       ret = ov9740_reg_write(client, OV9740_X_OUTPUT_SIZE_HI, width >> 8);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_X_OUTPUT_SIZE_LO, width & 0xff);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_Y_OUTPUT_SIZE_HI, height >> 8);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_Y_OUTPUT_SIZE_LO, height & 0xff);
+       if (ret)
+               goto done;
+
+       ret = ov9740_reg_write(client, OV9740_ISP_CTRL1E, scale_input_x >> 8);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_ISP_CTRL1F, scale_input_x & 0xff);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_ISP_CTRL20, scale_input_y >> 8);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_ISP_CTRL21, scale_input_y & 0xff);
+       if (ret)
+               goto done;
+
+       ret = ov9740_reg_write(client, OV9740_VFIFO_READ_START_HI,
+                              (scale_input_x - width) >> 8);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_VFIFO_READ_START_LO,
+                              (scale_input_x - width) & 0xff);
+       if (ret)
+               goto done;
+
+       ret = ov9740_reg_write(client, OV9740_ISP_CTRL00, 0xff);
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_ISP_CTRL01, 0xef |
+                                                         (scaling << 4));
+       if (ret)
+               goto done;
+       ret = ov9740_reg_write(client, OV9740_ISP_CTRL03, 0xff);
+
+done:
+       return ret;
+}
+
+/* set the format we will capture in */
+static int ov9740_s_fmt(struct v4l2_subdev *sd,
+                       struct v4l2_mbus_framefmt *mf)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct ov9740_priv *priv = to_ov9740(sd);
+       int ret;
+
+       ret = ov9740_reg_write_array(client, ov9740_defaults,
+                                    ARRAY_SIZE(ov9740_defaults));
+       if (ret < 0)
+               return ret;
+
+       ret = ov9740_set_res(client, mf->width, mf->height);
+       if (ret < 0)
+               return ret;
+
+       priv->current_mf = *mf;
+       return ret;
+}
+
+static int ov9740_set_fmt(struct v4l2_subdev *sd,
+               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_format *format)
+{
+       struct v4l2_mbus_framefmt *mf = &format->format;
+
+       if (format->pad)
+               return -EINVAL;
+
+       ov9740_res_roundup(&mf->width, &mf->height);
+
+       mf->field = V4L2_FIELD_NONE;
+       mf->code = MEDIA_BUS_FMT_YUYV8_2X8;
+       mf->colorspace = V4L2_COLORSPACE_SRGB;
+
+       if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+               return ov9740_s_fmt(sd, mf);
+       cfg->try_fmt = *mf;
+       return 0;
+}
+
+static int ov9740_enum_mbus_code(struct v4l2_subdev *sd,
+               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_mbus_code_enum *code)
+{
+       if (code->pad || code->index >= ARRAY_SIZE(ov9740_codes))
+               return -EINVAL;
+
+       code->code = ov9740_codes[code->index];
+
+       return 0;
+}
+
+static int ov9740_get_selection(struct v4l2_subdev *sd,
+               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_selection *sel)
+{
+       if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+               return -EINVAL;
+
+       switch (sel->target) {
+       case V4L2_SEL_TGT_CROP_BOUNDS:
+       case V4L2_SEL_TGT_CROP:
+               sel->r.left = 0;
+               sel->r.top = 0;
+               sel->r.width = OV9740_MAX_WIDTH;
+               sel->r.height = OV9740_MAX_HEIGHT;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+/* Set status of additional camera capabilities */
+static int ov9740_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct ov9740_priv *priv =
+               container_of(ctrl->handler, struct ov9740_priv, hdl);
+
+       switch (ctrl->id) {
+       case V4L2_CID_VFLIP:
+               priv->flag_vflip = ctrl->val;
+               break;
+       case V4L2_CID_HFLIP:
+               priv->flag_hflip = ctrl->val;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int ov9740_s_power(struct v4l2_subdev *sd, int on)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct ov9740_priv *priv = to_ov9740(sd);
+       int ret;
+
+       if (on) {
+               ret = soc_camera_power_on(&client->dev, ssdd, priv->clk);
+               if (ret < 0)
+                       return ret;
+
+               if (priv->current_enable) {
+                       ov9740_s_fmt(sd, &priv->current_mf);
+                       ov9740_s_stream(sd, 1);
+               }
+       } else {
+               if (priv->current_enable) {
+                       ov9740_s_stream(sd, 0);
+                       priv->current_enable = true;
+               }
+
+               soc_camera_power_off(&client->dev, ssdd, priv->clk);
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ov9740_get_register(struct v4l2_subdev *sd,
+                              struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret;
+       u8 val;
+
+       if (reg->reg & ~0xffff)
+               return -EINVAL;
+
+       reg->size = 2;
+
+       ret = ov9740_reg_read(client, reg->reg, &val);
+       if (ret)
+               return ret;
+
+       reg->val = (__u64)val;
+
+       return ret;
+}
+
+static int ov9740_set_register(struct v4l2_subdev *sd,
+                              const struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (reg->reg & ~0xffff || reg->val & ~0xff)
+               return -EINVAL;
+
+       return ov9740_reg_write(client, reg->reg, reg->val);
+}
+#endif
+
+static int ov9740_video_probe(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct ov9740_priv *priv = to_ov9740(sd);
+       u8 modelhi, modello;
+       int ret;
+
+       ret = ov9740_s_power(&priv->subdev, 1);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * check and show product ID and manufacturer ID
+        */
+       ret = ov9740_reg_read(client, OV9740_MODEL_ID_HI, &modelhi);
+       if (ret < 0)
+               goto done;
+
+       ret = ov9740_reg_read(client, OV9740_MODEL_ID_LO, &modello);
+       if (ret < 0)
+               goto done;
+
+       priv->model = (modelhi << 8) | modello;
+
+       ret = ov9740_reg_read(client, OV9740_REVISION_NUMBER, &priv->revision);
+       if (ret < 0)
+               goto done;
+
+       ret = ov9740_reg_read(client, OV9740_MANUFACTURER_ID, &priv->manid);
+       if (ret < 0)
+               goto done;
+
+       ret = ov9740_reg_read(client, OV9740_SMIA_VERSION, &priv->smiaver);
+       if (ret < 0)
+               goto done;
+
+       if (priv->model != 0x9740) {
+               ret = -ENODEV;
+               goto done;
+       }
+
+       dev_info(&client->dev, "ov9740 Model ID 0x%04x, Revision 0x%02x, Manufacturer 0x%02x, SMIA Version 0x%02x\n",
+                priv->model, priv->revision, priv->manid, priv->smiaver);
+
+       ret = v4l2_ctrl_handler_setup(&priv->hdl);
+
+done:
+       ov9740_s_power(&priv->subdev, 0);
+       return ret;
+}
+
+/* Request bus settings on camera side */
+static int ov9740_g_mbus_config(struct v4l2_subdev *sd,
+                               struct v4l2_mbus_config *cfg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+
+       cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
+               V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
+               V4L2_MBUS_DATA_ACTIVE_HIGH;
+       cfg->type = V4L2_MBUS_PARALLEL;
+       cfg->flags = soc_camera_apply_board_flags(ssdd, cfg);
+
+       return 0;
+}
+
+static const struct v4l2_subdev_video_ops ov9740_video_ops = {
+       .s_stream       = ov9740_s_stream,
+       .g_mbus_config  = ov9740_g_mbus_config,
+};
+
+static const struct v4l2_subdev_core_ops ov9740_core_ops = {
+       .s_power                = ov9740_s_power,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .g_register             = ov9740_get_register,
+       .s_register             = ov9740_set_register,
+#endif
+};
+
+static const struct v4l2_subdev_pad_ops ov9740_pad_ops = {
+       .enum_mbus_code = ov9740_enum_mbus_code,
+       .get_selection  = ov9740_get_selection,
+       .set_fmt        = ov9740_set_fmt,
+};
+
+static const struct v4l2_subdev_ops ov9740_subdev_ops = {
+       .core   = &ov9740_core_ops,
+       .video  = &ov9740_video_ops,
+       .pad    = &ov9740_pad_ops,
+};
+
+static const struct v4l2_ctrl_ops ov9740_ctrl_ops = {
+       .s_ctrl = ov9740_s_ctrl,
+};
+
+/*
+ * i2c_driver function
+ */
+static int ov9740_probe(struct i2c_client *client,
+                       const struct i2c_device_id *did)
+{
+       struct ov9740_priv *priv;
+       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       int ret;
+
+       if (!ssdd) {
+               dev_err(&client->dev, "Missing platform_data for driver\n");
+               return -EINVAL;
+       }
+
+       priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       v4l2_i2c_subdev_init(&priv->subdev, client, &ov9740_subdev_ops);
+       v4l2_ctrl_handler_init(&priv->hdl, 13);
+       v4l2_ctrl_new_std(&priv->hdl, &ov9740_ctrl_ops,
+                       V4L2_CID_VFLIP, 0, 1, 1, 0);
+       v4l2_ctrl_new_std(&priv->hdl, &ov9740_ctrl_ops,
+                       V4L2_CID_HFLIP, 0, 1, 1, 0);
+       priv->subdev.ctrl_handler = &priv->hdl;
+       if (priv->hdl.error)
+               return priv->hdl.error;
+
+       priv->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(priv->clk)) {
+               ret = PTR_ERR(priv->clk);
+               goto eclkget;
+       }
+
+       ret = ov9740_video_probe(client);
+       if (ret < 0) {
+               v4l2_clk_put(priv->clk);
+eclkget:
+               v4l2_ctrl_handler_free(&priv->hdl);
+       }
+
+       return ret;
+}
+
+static int ov9740_remove(struct i2c_client *client)
+{
+       struct ov9740_priv *priv = i2c_get_clientdata(client);
+
+       v4l2_clk_put(priv->clk);
+       v4l2_device_unregister_subdev(&priv->subdev);
+       v4l2_ctrl_handler_free(&priv->hdl);
+       return 0;
+}
+
+static const struct i2c_device_id ov9740_id[] = {
+       { "ov9740", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, ov9740_id);
+
+static struct i2c_driver ov9740_i2c_driver = {
+       .driver = {
+               .name = "ov9740",
+       },
+       .probe    = ov9740_probe,
+       .remove   = ov9740_remove,
+       .id_table = ov9740_id,
+};
+
+module_i2c_driver(ov9740_i2c_driver);
+
+MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV9740");
+MODULE_AUTHOR("Andrew Chew <achew@nvidia.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/soc_camera/soc_rj54n1cb0c.c b/drivers/media/i2c/soc_camera/soc_rj54n1cb0c.c
new file mode 100644 (file)
index 0000000..f0cb49a
--- /dev/null
@@ -0,0 +1,1415 @@
+/*
+ * Driver for RJ54N1CB0C CMOS Image Sensor from Sharp
+ *
+ * Copyright (C) 2009, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * 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.
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/videodev2.h>
+#include <linux/module.h>
+
+#include <media/i2c/rj54n1cb0c.h>
+#include <media/soc_camera.h>
+#include <media/v4l2-clk.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-ctrls.h>
+
+#define RJ54N1_DEV_CODE                        0x0400
+#define RJ54N1_DEV_CODE2               0x0401
+#define RJ54N1_OUT_SEL                 0x0403
+#define RJ54N1_XY_OUTPUT_SIZE_S_H      0x0404
+#define RJ54N1_X_OUTPUT_SIZE_S_L       0x0405
+#define RJ54N1_Y_OUTPUT_SIZE_S_L       0x0406
+#define RJ54N1_XY_OUTPUT_SIZE_P_H      0x0407
+#define RJ54N1_X_OUTPUT_SIZE_P_L       0x0408
+#define RJ54N1_Y_OUTPUT_SIZE_P_L       0x0409
+#define RJ54N1_LINE_LENGTH_PCK_S_H     0x040a
+#define RJ54N1_LINE_LENGTH_PCK_S_L     0x040b
+#define RJ54N1_LINE_LENGTH_PCK_P_H     0x040c
+#define RJ54N1_LINE_LENGTH_PCK_P_L     0x040d
+#define RJ54N1_RESIZE_N                        0x040e
+#define RJ54N1_RESIZE_N_STEP           0x040f
+#define RJ54N1_RESIZE_STEP             0x0410
+#define RJ54N1_RESIZE_HOLD_H           0x0411
+#define RJ54N1_RESIZE_HOLD_L           0x0412
+#define RJ54N1_H_OBEN_OFS              0x0413
+#define RJ54N1_V_OBEN_OFS              0x0414
+#define RJ54N1_RESIZE_CONTROL          0x0415
+#define RJ54N1_STILL_CONTROL           0x0417
+#define RJ54N1_INC_USE_SEL_H           0x0425
+#define RJ54N1_INC_USE_SEL_L           0x0426
+#define RJ54N1_MIRROR_STILL_MODE       0x0427
+#define RJ54N1_INIT_START              0x0428
+#define RJ54N1_SCALE_1_2_LEV           0x0429
+#define RJ54N1_SCALE_4_LEV             0x042a
+#define RJ54N1_Y_GAIN                  0x04d8
+#define RJ54N1_APT_GAIN_UP             0x04fa
+#define RJ54N1_RA_SEL_UL               0x0530
+#define RJ54N1_BYTE_SWAP               0x0531
+#define RJ54N1_OUT_SIGPO               0x053b
+#define RJ54N1_WB_SEL_WEIGHT_I         0x054e
+#define RJ54N1_BIT8_WB                 0x0569
+#define RJ54N1_HCAPS_WB                        0x056a
+#define RJ54N1_VCAPS_WB                        0x056b
+#define RJ54N1_HCAPE_WB                        0x056c
+#define RJ54N1_VCAPE_WB                        0x056d
+#define RJ54N1_EXPOSURE_CONTROL                0x058c
+#define RJ54N1_FRAME_LENGTH_S_H                0x0595
+#define RJ54N1_FRAME_LENGTH_S_L                0x0596
+#define RJ54N1_FRAME_LENGTH_P_H                0x0597
+#define RJ54N1_FRAME_LENGTH_P_L                0x0598
+#define RJ54N1_PEAK_H                  0x05b7
+#define RJ54N1_PEAK_50                 0x05b8
+#define RJ54N1_PEAK_60                 0x05b9
+#define RJ54N1_PEAK_DIFF               0x05ba
+#define RJ54N1_IOC                     0x05ef
+#define RJ54N1_TG_BYPASS               0x0700
+#define RJ54N1_PLL_L                   0x0701
+#define RJ54N1_PLL_N                   0x0702
+#define RJ54N1_PLL_EN                  0x0704
+#define RJ54N1_RATIO_TG                        0x0706
+#define RJ54N1_RATIO_T                 0x0707
+#define RJ54N1_RATIO_R                 0x0708
+#define RJ54N1_RAMP_TGCLK_EN           0x0709
+#define RJ54N1_OCLK_DSP                        0x0710
+#define RJ54N1_RATIO_OP                        0x0711
+#define RJ54N1_RATIO_O                 0x0712
+#define RJ54N1_OCLK_SEL_EN             0x0713
+#define RJ54N1_CLK_RST                 0x0717
+#define RJ54N1_RESET_STANDBY           0x0718
+#define RJ54N1_FWFLG                   0x07fe
+
+#define E_EXCLK                                (1 << 7)
+#define SOFT_STDBY                     (1 << 4)
+#define SEN_RSTX                       (1 << 2)
+#define TG_RSTX                                (1 << 1)
+#define DSP_RSTX                       (1 << 0)
+
+#define RESIZE_HOLD_SEL                        (1 << 2)
+#define RESIZE_GO                      (1 << 1)
+
+/*
+ * When cropping, the camera automatically centers the cropped region, there
+ * doesn't seem to be a way to specify an explicit location of the rectangle.
+ */
+#define RJ54N1_COLUMN_SKIP             0
+#define RJ54N1_ROW_SKIP                        0
+#define RJ54N1_MAX_WIDTH               1600
+#define RJ54N1_MAX_HEIGHT              1200
+
+#define PLL_L                          2
+#define PLL_N                          0x31
+
+/* I2C addresses: 0x50, 0x51, 0x60, 0x61 */
+
+/* RJ54N1CB0C has only one fixed colorspace per pixelcode */
+struct rj54n1_datafmt {
+       u32     code;
+       enum v4l2_colorspace            colorspace;
+};
+
+/* Find a data format by a pixel code in an array */
+static const struct rj54n1_datafmt *rj54n1_find_datafmt(
+       u32 code, const struct rj54n1_datafmt *fmt,
+       int n)
+{
+       int i;
+       for (i = 0; i < n; i++)
+               if (fmt[i].code == code)
+                       return fmt + i;
+
+       return NULL;
+}
+
+static const struct rj54n1_datafmt rj54n1_colour_fmts[] = {
+       {MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG},
+       {MEDIA_BUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG},
+       {MEDIA_BUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB},
+       {MEDIA_BUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB},
+       {MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
+       {MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE, V4L2_COLORSPACE_SRGB},
+       {MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE, V4L2_COLORSPACE_SRGB},
+       {MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE, V4L2_COLORSPACE_SRGB},
+       {MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB},
+};
+
+struct rj54n1_clock_div {
+       u8 ratio_tg;    /* can be 0 or an odd number */
+       u8 ratio_t;
+       u8 ratio_r;
+       u8 ratio_op;
+       u8 ratio_o;
+};
+
+struct rj54n1 {
+       struct v4l2_subdev subdev;
+       struct v4l2_ctrl_handler hdl;
+       struct v4l2_clk *clk;
+       struct rj54n1_clock_div clk_div;
+       const struct rj54n1_datafmt *fmt;
+       struct v4l2_rect rect;  /* Sensor window */
+       unsigned int tgclk_mhz;
+       bool auto_wb;
+       unsigned short width;   /* Output window */
+       unsigned short height;
+       unsigned short resize;  /* Sensor * 1024 / resize = Output */
+       unsigned short scale;
+       u8 bank;
+};
+
+struct rj54n1_reg_val {
+       u16 reg;
+       u8 val;
+};
+
+static const struct rj54n1_reg_val bank_4[] = {
+       {0x417, 0},
+       {0x42c, 0},
+       {0x42d, 0xf0},
+       {0x42e, 0},
+       {0x42f, 0x50},
+       {0x430, 0xf5},
+       {0x431, 0x16},
+       {0x432, 0x20},
+       {0x433, 0},
+       {0x434, 0xc8},
+       {0x43c, 8},
+       {0x43e, 0x90},
+       {0x445, 0x83},
+       {0x4ba, 0x58},
+       {0x4bb, 4},
+       {0x4bc, 0x20},
+       {0x4db, 4},
+       {0x4fe, 2},
+};
+
+static const struct rj54n1_reg_val bank_5[] = {
+       {0x514, 0},
+       {0x516, 0},
+       {0x518, 0},
+       {0x51a, 0},
+       {0x51d, 0xff},
+       {0x56f, 0x28},
+       {0x575, 0x40},
+       {0x5bc, 0x48},
+       {0x5c1, 6},
+       {0x5e5, 0x11},
+       {0x5e6, 0x43},
+       {0x5e7, 0x33},
+       {0x5e8, 0x21},
+       {0x5e9, 0x30},
+       {0x5ea, 0x0},
+       {0x5eb, 0xa5},
+       {0x5ec, 0xff},
+       {0x5fe, 2},
+};
+
+static const struct rj54n1_reg_val bank_7[] = {
+       {0x70a, 0},
+       {0x714, 0xff},
+       {0x715, 0xff},
+       {0x716, 0x1f},
+       {0x7FE, 2},
+};
+
+static const struct rj54n1_reg_val bank_8[] = {
+       {0x800, 0x00},
+       {0x801, 0x01},
+       {0x802, 0x61},
+       {0x805, 0x00},
+       {0x806, 0x00},
+       {0x807, 0x00},
+       {0x808, 0x00},
+       {0x809, 0x01},
+       {0x80A, 0x61},
+       {0x80B, 0x00},
+       {0x80C, 0x01},
+       {0x80D, 0x00},
+       {0x80E, 0x00},
+       {0x80F, 0x00},
+       {0x810, 0x00},
+       {0x811, 0x01},
+       {0x812, 0x61},
+       {0x813, 0x00},
+       {0x814, 0x11},
+       {0x815, 0x00},
+       {0x816, 0x41},
+       {0x817, 0x00},
+       {0x818, 0x51},
+       {0x819, 0x01},
+       {0x81A, 0x1F},
+       {0x81B, 0x00},
+       {0x81C, 0x01},
+       {0x81D, 0x00},
+       {0x81E, 0x11},
+       {0x81F, 0x00},
+       {0x820, 0x41},
+       {0x821, 0x00},
+       {0x822, 0x51},
+       {0x823, 0x00},
+       {0x824, 0x00},
+       {0x825, 0x00},
+       {0x826, 0x47},
+       {0x827, 0x01},
+       {0x828, 0x4F},
+       {0x829, 0x00},
+       {0x82A, 0x00},
+       {0x82B, 0x00},
+       {0x82C, 0x30},
+       {0x82D, 0x00},
+       {0x82E, 0x40},
+       {0x82F, 0x00},
+       {0x830, 0xB3},
+       {0x831, 0x00},
+       {0x832, 0xE3},
+       {0x833, 0x00},
+       {0x834, 0x00},
+       {0x835, 0x00},
+       {0x836, 0x00},
+       {0x837, 0x00},
+       {0x838, 0x00},
+       {0x839, 0x01},
+       {0x83A, 0x61},
+       {0x83B, 0x00},
+       {0x83C, 0x01},
+       {0x83D, 0x00},
+       {0x83E, 0x00},
+       {0x83F, 0x00},
+       {0x840, 0x00},
+       {0x841, 0x01},
+       {0x842, 0x61},
+       {0x843, 0x00},
+       {0x844, 0x1D},
+       {0x845, 0x00},
+       {0x846, 0x00},
+       {0x847, 0x00},
+       {0x848, 0x00},
+       {0x849, 0x01},
+       {0x84A, 0x1F},
+       {0x84B, 0x00},
+       {0x84C, 0x05},
+       {0x84D, 0x00},
+       {0x84E, 0x19},
+       {0x84F, 0x01},
+       {0x850, 0x21},
+       {0x851, 0x01},
+       {0x852, 0x5D},
+       {0x853, 0x00},
+       {0x854, 0x00},
+       {0x855, 0x00},
+       {0x856, 0x19},
+       {0x857, 0x01},
+       {0x858, 0x21},
+       {0x859, 0x00},
+       {0x85A, 0x00},
+       {0x85B, 0x00},
+       {0x85C, 0x00},
+       {0x85D, 0x00},
+       {0x85E, 0x00},
+       {0x85F, 0x00},
+       {0x860, 0xB3},
+       {0x861, 0x00},
+       {0x862, 0xE3},
+       {0x863, 0x00},
+       {0x864, 0x00},
+       {0x865, 0x00},
+       {0x866, 0x00},
+       {0x867, 0x00},
+       {0x868, 0x00},
+       {0x869, 0xE2},
+       {0x86A, 0x00},
+       {0x86B, 0x01},
+       {0x86C, 0x06},
+       {0x86D, 0x00},
+       {0x86E, 0x00},
+       {0x86F, 0x00},
+       {0x870, 0x60},
+       {0x871, 0x8C},
+       {0x872, 0x10},
+       {0x873, 0x00},
+       {0x874, 0xE0},
+       {0x875, 0x00},
+       {0x876, 0x27},
+       {0x877, 0x01},
+       {0x878, 0x00},
+       {0x879, 0x00},
+       {0x87A, 0x00},
+       {0x87B, 0x03},
+       {0x87C, 0x00},
+       {0x87D, 0x00},
+       {0x87E, 0x00},
+       {0x87F, 0x00},
+       {0x880, 0x00},
+       {0x881, 0x00},
+       {0x882, 0x00},
+       {0x883, 0x00},
+       {0x884, 0x00},
+       {0x885, 0x00},
+       {0x886, 0xF8},
+       {0x887, 0x00},
+       {0x888, 0x03},
+       {0x889, 0x00},
+       {0x88A, 0x64},
+       {0x88B, 0x00},
+       {0x88C, 0x03},
+       {0x88D, 0x00},
+       {0x88E, 0xB1},
+       {0x88F, 0x00},
+       {0x890, 0x03},
+       {0x891, 0x01},
+       {0x892, 0x1D},
+       {0x893, 0x00},
+       {0x894, 0x03},
+       {0x895, 0x01},
+       {0x896, 0x4B},
+       {0x897, 0x00},
+       {0x898, 0xE5},
+       {0x899, 0x00},
+       {0x89A, 0x01},
+       {0x89B, 0x00},
+       {0x89C, 0x01},
+       {0x89D, 0x04},
+       {0x89E, 0xC8},
+       {0x89F, 0x00},
+       {0x8A0, 0x01},
+       {0x8A1, 0x01},
+       {0x8A2, 0x61},
+       {0x8A3, 0x00},
+       {0x8A4, 0x01},
+       {0x8A5, 0x00},
+       {0x8A6, 0x00},
+       {0x8A7, 0x00},
+       {0x8A8, 0x00},
+       {0x8A9, 0x00},
+       {0x8AA, 0x7F},
+       {0x8AB, 0x03},
+       {0x8AC, 0x00},
+       {0x8AD, 0x00},
+       {0x8AE, 0x00},
+       {0x8AF, 0x00},
+       {0x8B0, 0x00},
+       {0x8B1, 0x00},
+       {0x8B6, 0x00},
+       {0x8B7, 0x01},
+       {0x8B8, 0x00},
+       {0x8B9, 0x00},
+       {0x8BA, 0x02},
+       {0x8BB, 0x00},
+       {0x8BC, 0xFF},
+       {0x8BD, 0x00},
+       {0x8FE, 2},
+};
+
+static const struct rj54n1_reg_val bank_10[] = {
+       {0x10bf, 0x69}
+};
+
+/* Clock dividers - these are default register values, divider = register + 1 */
+static const struct rj54n1_clock_div clk_div = {
+       .ratio_tg       = 3 /* default: 5 */,
+       .ratio_t        = 4 /* default: 1 */,
+       .ratio_r        = 4 /* default: 0 */,
+       .ratio_op       = 1 /* default: 5 */,
+       .ratio_o        = 9 /* default: 0 */,
+};
+
+static struct rj54n1 *to_rj54n1(const struct i2c_client *client)
+{
+       return container_of(i2c_get_clientdata(client), struct rj54n1, subdev);
+}
+
+static int reg_read(struct i2c_client *client, const u16 reg)
+{
+       struct rj54n1 *rj54n1 = to_rj54n1(client);
+       int ret;
+
+       /* set bank */
+       if (rj54n1->bank != reg >> 8) {
+               dev_dbg(&client->dev, "[0x%x] = 0x%x\n", 0xff, reg >> 8);
+               ret = i2c_smbus_write_byte_data(client, 0xff, reg >> 8);
+               if (ret < 0)
+                       return ret;
+               rj54n1->bank = reg >> 8;
+       }
+       return i2c_smbus_read_byte_data(client, reg & 0xff);
+}
+
+static int reg_write(struct i2c_client *client, const u16 reg,
+                    const u8 data)
+{
+       struct rj54n1 *rj54n1 = to_rj54n1(client);
+       int ret;
+
+       /* set bank */
+       if (rj54n1->bank != reg >> 8) {
+               dev_dbg(&client->dev, "[0x%x] = 0x%x\n", 0xff, reg >> 8);
+               ret = i2c_smbus_write_byte_data(client, 0xff, reg >> 8);
+               if (ret < 0)
+                       return ret;
+               rj54n1->bank = reg >> 8;
+       }
+       dev_dbg(&client->dev, "[0x%x] = 0x%x\n", reg & 0xff, data);
+       return i2c_smbus_write_byte_data(client, reg & 0xff, data);
+}
+
+static int reg_set(struct i2c_client *client, const u16 reg,
+                  const u8 data, const u8 mask)
+{
+       int ret;
+
+       ret = reg_read(client, reg);
+       if (ret < 0)
+               return ret;
+       return reg_write(client, reg, (ret & ~mask) | (data & mask));
+}
+
+static int reg_write_multiple(struct i2c_client *client,
+                             const struct rj54n1_reg_val *rv, const int n)
+{
+       int i, ret;
+
+       for (i = 0; i < n; i++) {
+               ret = reg_write(client, rv->reg, rv->val);
+               if (ret < 0)
+                       return ret;
+               rv++;
+       }
+
+       return 0;
+}
+
+static int rj54n1_enum_mbus_code(struct v4l2_subdev *sd,
+               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_mbus_code_enum *code)
+{
+       if (code->pad || code->index >= ARRAY_SIZE(rj54n1_colour_fmts))
+               return -EINVAL;
+
+       code->code = rj54n1_colour_fmts[code->index].code;
+       return 0;
+}
+
+static int rj54n1_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       /* Switch between preview and still shot modes */
+       return reg_set(client, RJ54N1_STILL_CONTROL, (!enable) << 7, 0x80);
+}
+
+static int rj54n1_set_rect(struct i2c_client *client,
+                          u16 reg_x, u16 reg_y, u16 reg_xy,
+                          u32 width, u32 height)
+{
+       int ret;
+
+       ret = reg_write(client, reg_xy,
+                       ((width >> 4) & 0x70) |
+                       ((height >> 8) & 7));
+
+       if (!ret)
+               ret = reg_write(client, reg_x, width & 0xff);
+       if (!ret)
+               ret = reg_write(client, reg_y, height & 0xff);
+
+       return ret;
+}
+
+/*
+ * Some commands, specifically certain initialisation sequences, require
+ * a commit operation.
+ */
+static int rj54n1_commit(struct i2c_client *client)
+{
+       int ret = reg_write(client, RJ54N1_INIT_START, 1);
+       msleep(10);
+       if (!ret)
+               ret = reg_write(client, RJ54N1_INIT_START, 0);
+       return ret;
+}
+
+static int rj54n1_sensor_scale(struct v4l2_subdev *sd, s32 *in_w, s32 *in_h,
+                              s32 *out_w, s32 *out_h);
+
+static int rj54n1_set_selection(struct v4l2_subdev *sd,
+                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_selection *sel)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct rj54n1 *rj54n1 = to_rj54n1(client);
+       const struct v4l2_rect *rect = &sel->r;
+       int dummy = 0, output_w, output_h,
+               input_w = rect->width, input_h = rect->height;
+       int ret;
+
+       if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
+           sel->target != V4L2_SEL_TGT_CROP)
+               return -EINVAL;
+
+       /* arbitrary minimum width and height, edges unimportant */
+       soc_camera_limit_side(&dummy, &input_w,
+                    RJ54N1_COLUMN_SKIP, 8, RJ54N1_MAX_WIDTH);
+
+       soc_camera_limit_side(&dummy, &input_h,
+                    RJ54N1_ROW_SKIP, 8, RJ54N1_MAX_HEIGHT);
+
+       output_w = (input_w * 1024 + rj54n1->resize / 2) / rj54n1->resize;
+       output_h = (input_h * 1024 + rj54n1->resize / 2) / rj54n1->resize;
+
+       dev_dbg(&client->dev, "Scaling for %dx%d : %u = %dx%d\n",
+               input_w, input_h, rj54n1->resize, output_w, output_h);
+
+       ret = rj54n1_sensor_scale(sd, &input_w, &input_h, &output_w, &output_h);
+       if (ret < 0)
+               return ret;
+
+       rj54n1->width           = output_w;
+       rj54n1->height          = output_h;
+       rj54n1->resize          = ret;
+       rj54n1->rect.width      = input_w;
+       rj54n1->rect.height     = input_h;
+
+       return 0;
+}
+
+static int rj54n1_get_selection(struct v4l2_subdev *sd,
+                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_selection *sel)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct rj54n1 *rj54n1 = to_rj54n1(client);
+
+       if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+               return -EINVAL;
+
+       switch (sel->target) {
+       case V4L2_SEL_TGT_CROP_BOUNDS:
+               sel->r.left = RJ54N1_COLUMN_SKIP;
+               sel->r.top = RJ54N1_ROW_SKIP;
+               sel->r.width = RJ54N1_MAX_WIDTH;
+               sel->r.height = RJ54N1_MAX_HEIGHT;
+               return 0;
+       case V4L2_SEL_TGT_CROP:
+               sel->r = rj54n1->rect;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int rj54n1_get_fmt(struct v4l2_subdev *sd,
+               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_format *format)
+{
+       struct v4l2_mbus_framefmt *mf = &format->format;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct rj54n1 *rj54n1 = to_rj54n1(client);
+
+       if (format->pad)
+               return -EINVAL;
+
+       mf->code        = rj54n1->fmt->code;
+       mf->colorspace  = rj54n1->fmt->colorspace;
+       mf->field       = V4L2_FIELD_NONE;
+       mf->width       = rj54n1->width;
+       mf->height      = rj54n1->height;
+
+       return 0;
+}
+
+/*
+ * The actual geometry configuration routine. It scales the input window into
+ * the output one, updates the window sizes and returns an error or the resize
+ * coefficient on success. Note: we only use the "Fixed Scaling" on this camera.
+ */
+static int rj54n1_sensor_scale(struct v4l2_subdev *sd, s32 *in_w, s32 *in_h,
+                              s32 *out_w, s32 *out_h)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct rj54n1 *rj54n1 = to_rj54n1(client);
+       unsigned int skip, resize, input_w = *in_w, input_h = *in_h,
+               output_w = *out_w, output_h = *out_h;
+       u16 inc_sel, wb_bit8, wb_left, wb_right, wb_top, wb_bottom;
+       unsigned int peak, peak_50, peak_60;
+       int ret;
+
+       /*
+        * We have a problem with crops, where the window is larger than 512x384
+        * and output window is larger than a half of the input one. In this
+        * case we have to either reduce the input window to equal or below
+        * 512x384 or the output window to equal or below 1/2 of the input.
+        */
+       if (output_w > max(512U, input_w / 2)) {
+               if (2 * output_w > RJ54N1_MAX_WIDTH) {
+                       input_w = RJ54N1_MAX_WIDTH;
+                       output_w = RJ54N1_MAX_WIDTH / 2;
+               } else {
+                       input_w = output_w * 2;
+               }
+
+               dev_dbg(&client->dev, "Adjusted output width: in %u, out %u\n",
+                       input_w, output_w);
+       }
+
+       if (output_h > max(384U, input_h / 2)) {
+               if (2 * output_h > RJ54N1_MAX_HEIGHT) {
+                       input_h = RJ54N1_MAX_HEIGHT;
+                       output_h = RJ54N1_MAX_HEIGHT / 2;
+               } else {
+                       input_h = output_h * 2;
+               }
+
+               dev_dbg(&client->dev, "Adjusted output height: in %u, out %u\n",
+                       input_h, output_h);
+       }
+
+       /* Idea: use the read mode for snapshots, handle separate geometries */
+       ret = rj54n1_set_rect(client, RJ54N1_X_OUTPUT_SIZE_S_L,
+                             RJ54N1_Y_OUTPUT_SIZE_S_L,
+                             RJ54N1_XY_OUTPUT_SIZE_S_H, output_w, output_h);
+       if (!ret)
+               ret = rj54n1_set_rect(client, RJ54N1_X_OUTPUT_SIZE_P_L,
+                             RJ54N1_Y_OUTPUT_SIZE_P_L,
+                             RJ54N1_XY_OUTPUT_SIZE_P_H, output_w, output_h);
+
+       if (ret < 0)
+               return ret;
+
+       if (output_w > input_w && output_h > input_h) {
+               input_w = output_w;
+               input_h = output_h;
+
+               resize = 1024;
+       } else {
+               unsigned int resize_x, resize_y;
+               resize_x = (input_w * 1024 + output_w / 2) / output_w;
+               resize_y = (input_h * 1024 + output_h / 2) / output_h;
+
+               /* We want max(resize_x, resize_y), check if it still fits */
+               if (resize_x > resize_y &&
+                   (output_h * resize_x + 512) / 1024 > RJ54N1_MAX_HEIGHT)
+                       resize = (RJ54N1_MAX_HEIGHT * 1024 + output_h / 2) /
+                               output_h;
+               else if (resize_y > resize_x &&
+                        (output_w * resize_y + 512) / 1024 > RJ54N1_MAX_WIDTH)
+                       resize = (RJ54N1_MAX_WIDTH * 1024 + output_w / 2) /
+                               output_w;
+               else
+                       resize = max(resize_x, resize_y);
+
+               /* Prohibited value ranges */
+               switch (resize) {
+               case 2040 ... 2047:
+                       resize = 2039;
+                       break;
+               case 4080 ... 4095:
+                       resize = 4079;
+                       break;
+               case 8160 ... 8191:
+                       resize = 8159;
+                       break;
+               case 16320 ... 16384:
+                       resize = 16319;
+               }
+       }
+
+       /* Set scaling */
+       ret = reg_write(client, RJ54N1_RESIZE_HOLD_L, resize & 0xff);
+       if (!ret)
+               ret = reg_write(client, RJ54N1_RESIZE_HOLD_H, resize >> 8);
+
+       if (ret < 0)
+               return ret;
+
+       /*
+        * Configure a skipping bitmask. The sensor will select a skipping value
+        * among set bits automatically. This is very unclear in the datasheet
+        * too. I was told, in this register one enables all skipping values,
+        * that are required for a specific resize, and the camera selects
+        * automatically, which ones to use. But it is unclear how to identify,
+        * which cropping values are needed. Secondly, why don't we just set all
+        * bits and let the camera choose? Would it increase processing time and
+        * reduce the framerate? Using 0xfffc for INC_USE_SEL doesn't seem to
+        * improve the image quality or stability for larger frames (see comment
+        * above), but I didn't check the framerate.
+        */
+       skip = min(resize / 1024, 15U);
+
+       inc_sel = 1 << skip;
+
+       if (inc_sel <= 2)
+               inc_sel = 0xc;
+       else if (resize & 1023 && skip < 15)
+               inc_sel |= 1 << (skip + 1);
+
+       ret = reg_write(client, RJ54N1_INC_USE_SEL_L, inc_sel & 0xfc);
+       if (!ret)
+               ret = reg_write(client, RJ54N1_INC_USE_SEL_H, inc_sel >> 8);
+
+       if (!rj54n1->auto_wb) {
+               /* Auto white balance window */
+               wb_left   = output_w / 16;
+               wb_right  = (3 * output_w / 4 - 3) / 4;
+               wb_top    = output_h / 16;
+               wb_bottom = (3 * output_h / 4 - 3) / 4;
+               wb_bit8   = ((wb_left >> 2) & 0x40) | ((wb_top >> 4) & 0x10) |
+                       ((wb_right >> 6) & 4) | ((wb_bottom >> 8) & 1);
+
+               if (!ret)
+                       ret = reg_write(client, RJ54N1_BIT8_WB, wb_bit8);
+               if (!ret)
+                       ret = reg_write(client, RJ54N1_HCAPS_WB, wb_left);
+               if (!ret)
+                       ret = reg_write(client, RJ54N1_VCAPS_WB, wb_top);
+               if (!ret)
+                       ret = reg_write(client, RJ54N1_HCAPE_WB, wb_right);
+               if (!ret)
+                       ret = reg_write(client, RJ54N1_VCAPE_WB, wb_bottom);
+       }
+
+       /* Antiflicker */
+       peak = 12 * RJ54N1_MAX_WIDTH * (1 << 14) * resize / rj54n1->tgclk_mhz /
+               10000;
+       peak_50 = peak / 6;
+       peak_60 = peak / 5;
+
+       if (!ret)
+               ret = reg_write(client, RJ54N1_PEAK_H,
+                               ((peak_50 >> 4) & 0xf0) | (peak_60 >> 8));
+       if (!ret)
+               ret = reg_write(client, RJ54N1_PEAK_50, peak_50);
+       if (!ret)
+               ret = reg_write(client, RJ54N1_PEAK_60, peak_60);
+       if (!ret)
+               ret = reg_write(client, RJ54N1_PEAK_DIFF, peak / 150);
+
+       /* Start resizing */
+       if (!ret)
+               ret = reg_write(client, RJ54N1_RESIZE_CONTROL,
+                               RESIZE_HOLD_SEL | RESIZE_GO | 1);
+
+       if (ret < 0)
+               return ret;
+
+       /* Constant taken from manufacturer's example */
+       msleep(230);
+
+       ret = reg_write(client, RJ54N1_RESIZE_CONTROL, RESIZE_HOLD_SEL | 1);
+       if (ret < 0)
+               return ret;
+
+       *in_w = (output_w * resize + 512) / 1024;
+       *in_h = (output_h * resize + 512) / 1024;
+       *out_w = output_w;
+       *out_h = output_h;
+
+       dev_dbg(&client->dev, "Scaled for %dx%d : %u = %ux%u, skip %u\n",
+               *in_w, *in_h, resize, output_w, output_h, skip);
+
+       return resize;
+}
+
+static int rj54n1_set_clock(struct i2c_client *client)
+{
+       struct rj54n1 *rj54n1 = to_rj54n1(client);
+       int ret;
+
+       /* Enable external clock */
+       ret = reg_write(client, RJ54N1_RESET_STANDBY, E_EXCLK | SOFT_STDBY);
+       /* Leave stand-by. Note: use this when implementing suspend / resume */
+       if (!ret)
+               ret = reg_write(client, RJ54N1_RESET_STANDBY, E_EXCLK);
+
+       if (!ret)
+               ret = reg_write(client, RJ54N1_PLL_L, PLL_L);
+       if (!ret)
+               ret = reg_write(client, RJ54N1_PLL_N, PLL_N);
+
+       /* TGCLK dividers */
+       if (!ret)
+               ret = reg_write(client, RJ54N1_RATIO_TG,
+                               rj54n1->clk_div.ratio_tg);
+       if (!ret)
+               ret = reg_write(client, RJ54N1_RATIO_T,
+                               rj54n1->clk_div.ratio_t);
+       if (!ret)
+               ret = reg_write(client, RJ54N1_RATIO_R,
+                               rj54n1->clk_div.ratio_r);
+
+       /* Enable TGCLK & RAMP */
+       if (!ret)
+               ret = reg_write(client, RJ54N1_RAMP_TGCLK_EN, 3);
+
+       /* Disable clock output */
+       if (!ret)
+               ret = reg_write(client, RJ54N1_OCLK_DSP, 0);
+
+       /* Set divisors */
+       if (!ret)
+               ret = reg_write(client, RJ54N1_RATIO_OP,
+                               rj54n1->clk_div.ratio_op);
+       if (!ret)
+               ret = reg_write(client, RJ54N1_RATIO_O,
+                               rj54n1->clk_div.ratio_o);
+
+       /* Enable OCLK */
+       if (!ret)
+               ret = reg_write(client, RJ54N1_OCLK_SEL_EN, 1);
+
+       /* Use PLL for Timing Generator, write 2 to reserved bits */
+       if (!ret)
+               ret = reg_write(client, RJ54N1_TG_BYPASS, 2);
+
+       /* Take sensor out of reset */
+       if (!ret)
+               ret = reg_write(client, RJ54N1_RESET_STANDBY,
+                               E_EXCLK | SEN_RSTX);
+       /* Enable PLL */
+       if (!ret)
+               ret = reg_write(client, RJ54N1_PLL_EN, 1);
+
+       /* Wait for PLL to stabilise */
+       msleep(10);
+
+       /* Enable clock to frequency divider */
+       if (!ret)
+               ret = reg_write(client, RJ54N1_CLK_RST, 1);
+
+       if (!ret)
+               ret = reg_read(client, RJ54N1_CLK_RST);
+       if (ret != 1) {
+               dev_err(&client->dev,
+                       "Resetting RJ54N1CB0C clock failed: %d!\n", ret);
+               return -EIO;
+       }
+
+       /* Start the PLL */
+       ret = reg_set(client, RJ54N1_OCLK_DSP, 1, 1);
+
+       /* Enable OCLK */
+       if (!ret)
+               ret = reg_write(client, RJ54N1_OCLK_SEL_EN, 1);
+
+       return ret;
+}
+
+static int rj54n1_reg_init(struct i2c_client *client)
+{
+       struct rj54n1 *rj54n1 = to_rj54n1(client);
+       int ret = rj54n1_set_clock(client);
+
+       if (!ret)
+               ret = reg_write_multiple(client, bank_7, ARRAY_SIZE(bank_7));
+       if (!ret)
+               ret = reg_write_multiple(client, bank_10, ARRAY_SIZE(bank_10));
+
+       /* Set binning divisors */
+       if (!ret)
+               ret = reg_write(client, RJ54N1_SCALE_1_2_LEV, 3 | (7 << 4));
+       if (!ret)
+               ret = reg_write(client, RJ54N1_SCALE_4_LEV, 0xf);
+
+       /* Switch to fixed resize mode */
+       if (!ret)
+               ret = reg_write(client, RJ54N1_RESIZE_CONTROL,
+                               RESIZE_HOLD_SEL | 1);
+
+       /* Set gain */
+       if (!ret)
+               ret = reg_write(client, RJ54N1_Y_GAIN, 0x84);
+
+       /*
+        * Mirror the image back: default is upside down and left-to-right...
+        * Set manual preview / still shot switching
+        */
+       if (!ret)
+               ret = reg_write(client, RJ54N1_MIRROR_STILL_MODE, 0x27);
+
+       if (!ret)
+               ret = reg_write_multiple(client, bank_4, ARRAY_SIZE(bank_4));
+
+       /* Auto exposure area */
+       if (!ret)
+               ret = reg_write(client, RJ54N1_EXPOSURE_CONTROL, 0x80);
+       /* Check current auto WB config */
+       if (!ret)
+               ret = reg_read(client, RJ54N1_WB_SEL_WEIGHT_I);
+       if (ret >= 0) {
+               rj54n1->auto_wb = ret & 0x80;
+               ret = reg_write_multiple(client, bank_5, ARRAY_SIZE(bank_5));
+       }
+       if (!ret)
+               ret = reg_write_multiple(client, bank_8, ARRAY_SIZE(bank_8));
+
+       if (!ret)
+               ret = reg_write(client, RJ54N1_RESET_STANDBY,
+                               E_EXCLK | DSP_RSTX | SEN_RSTX);
+
+       /* Commit init */
+       if (!ret)
+               ret = rj54n1_commit(client);
+
+       /* Take DSP, TG, sensor out of reset */
+       if (!ret)
+               ret = reg_write(client, RJ54N1_RESET_STANDBY,
+                               E_EXCLK | DSP_RSTX | TG_RSTX | SEN_RSTX);
+
+       /* Start register update? Same register as 0x?FE in many bank_* sets */
+       if (!ret)
+               ret = reg_write(client, RJ54N1_FWFLG, 2);
+
+       /* Constant taken from manufacturer's example */
+       msleep(700);
+
+       return ret;
+}
+
+static int rj54n1_set_fmt(struct v4l2_subdev *sd,
+               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_format *format)
+{
+       struct v4l2_mbus_framefmt *mf = &format->format;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct rj54n1 *rj54n1 = to_rj54n1(client);
+       const struct rj54n1_datafmt *fmt;
+       int output_w, output_h, max_w, max_h,
+               input_w = rj54n1->rect.width, input_h = rj54n1->rect.height;
+       int align = mf->code == MEDIA_BUS_FMT_SBGGR10_1X10 ||
+               mf->code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE ||
+               mf->code == MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE ||
+               mf->code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE ||
+               mf->code == MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE;
+       int ret;
+
+       if (format->pad)
+               return -EINVAL;
+
+       dev_dbg(&client->dev, "%s: code = %d, width = %u, height = %u\n",
+               __func__, mf->code, mf->width, mf->height);
+
+       fmt = rj54n1_find_datafmt(mf->code, rj54n1_colour_fmts,
+                                 ARRAY_SIZE(rj54n1_colour_fmts));
+       if (!fmt) {
+               fmt = rj54n1->fmt;
+               mf->code = fmt->code;
+       }
+
+       mf->field       = V4L2_FIELD_NONE;
+       mf->colorspace  = fmt->colorspace;
+
+       v4l_bound_align_image(&mf->width, 112, RJ54N1_MAX_WIDTH, align,
+                             &mf->height, 84, RJ54N1_MAX_HEIGHT, align, 0);
+
+       if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+               cfg->try_fmt = *mf;
+               return 0;
+       }
+
+       /*
+        * Verify if the sensor has just been powered on. TODO: replace this
+        * with proper PM, when a suitable API is available.
+        */
+       ret = reg_read(client, RJ54N1_RESET_STANDBY);
+       if (ret < 0)
+               return ret;
+
+       if (!(ret & E_EXCLK)) {
+               ret = rj54n1_reg_init(client);
+               if (ret < 0)
+                       return ret;
+       }
+
+       /* RA_SEL_UL is only relevant for raw modes, ignored otherwise. */
+       switch (mf->code) {
+       case MEDIA_BUS_FMT_YUYV8_2X8:
+               ret = reg_write(client, RJ54N1_OUT_SEL, 0);
+               if (!ret)
+                       ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8);
+               break;
+       case MEDIA_BUS_FMT_YVYU8_2X8:
+               ret = reg_write(client, RJ54N1_OUT_SEL, 0);
+               if (!ret)
+                       ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8);
+               break;
+       case MEDIA_BUS_FMT_RGB565_2X8_LE:
+               ret = reg_write(client, RJ54N1_OUT_SEL, 0x11);
+               if (!ret)
+                       ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8);
+               break;
+       case MEDIA_BUS_FMT_RGB565_2X8_BE:
+               ret = reg_write(client, RJ54N1_OUT_SEL, 0x11);
+               if (!ret)
+                       ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8);
+               break;
+       case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE:
+               ret = reg_write(client, RJ54N1_OUT_SEL, 4);
+               if (!ret)
+                       ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8);
+               if (!ret)
+                       ret = reg_write(client, RJ54N1_RA_SEL_UL, 0);
+               break;
+       case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE:
+               ret = reg_write(client, RJ54N1_OUT_SEL, 4);
+               if (!ret)
+                       ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8);
+               if (!ret)
+                       ret = reg_write(client, RJ54N1_RA_SEL_UL, 8);
+               break;
+       case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE:
+               ret = reg_write(client, RJ54N1_OUT_SEL, 4);
+               if (!ret)
+                       ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8);
+               if (!ret)
+                       ret = reg_write(client, RJ54N1_RA_SEL_UL, 0);
+               break;
+       case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE:
+               ret = reg_write(client, RJ54N1_OUT_SEL, 4);
+               if (!ret)
+                       ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8);
+               if (!ret)
+                       ret = reg_write(client, RJ54N1_RA_SEL_UL, 8);
+               break;
+       case MEDIA_BUS_FMT_SBGGR10_1X10:
+               ret = reg_write(client, RJ54N1_OUT_SEL, 5);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       /* Special case: a raw mode with 10 bits of data per clock tick */
+       if (!ret)
+               ret = reg_set(client, RJ54N1_OCLK_SEL_EN,
+                             (mf->code == MEDIA_BUS_FMT_SBGGR10_1X10) << 1, 2);
+
+       if (ret < 0)
+               return ret;
+
+       /* Supported scales 1:1 >= scale > 1:16 */
+       max_w = mf->width * (16 * 1024 - 1) / 1024;
+       if (input_w > max_w)
+               input_w = max_w;
+       max_h = mf->height * (16 * 1024 - 1) / 1024;
+       if (input_h > max_h)
+               input_h = max_h;
+
+       output_w = mf->width;
+       output_h = mf->height;
+
+       ret = rj54n1_sensor_scale(sd, &input_w, &input_h, &output_w, &output_h);
+       if (ret < 0)
+               return ret;
+
+       fmt = rj54n1_find_datafmt(mf->code, rj54n1_colour_fmts,
+                                 ARRAY_SIZE(rj54n1_colour_fmts));
+
+       rj54n1->fmt             = fmt;
+       rj54n1->resize          = ret;
+       rj54n1->rect.width      = input_w;
+       rj54n1->rect.height     = input_h;
+       rj54n1->width           = output_w;
+       rj54n1->height          = output_h;
+
+       mf->width               = output_w;
+       mf->height              = output_h;
+       mf->field               = V4L2_FIELD_NONE;
+       mf->colorspace          = fmt->colorspace;
+
+       return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int rj54n1_g_register(struct v4l2_subdev *sd,
+                            struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (reg->reg < 0x400 || reg->reg > 0x1fff)
+               /* Registers > 0x0800 are only available from Sharp support */
+               return -EINVAL;
+
+       reg->size = 1;
+       reg->val = reg_read(client, reg->reg);
+
+       if (reg->val > 0xff)
+               return -EIO;
+
+       return 0;
+}
+
+static int rj54n1_s_register(struct v4l2_subdev *sd,
+                            const struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (reg->reg < 0x400 || reg->reg > 0x1fff)
+               /* Registers >= 0x0800 are only available from Sharp support */
+               return -EINVAL;
+
+       if (reg_write(client, reg->reg, reg->val) < 0)
+               return -EIO;
+
+       return 0;
+}
+#endif
+
+static int rj54n1_s_power(struct v4l2_subdev *sd, int on)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct rj54n1 *rj54n1 = to_rj54n1(client);
+
+       return soc_camera_set_power(&client->dev, ssdd, rj54n1->clk, on);
+}
+
+static int rj54n1_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct rj54n1 *rj54n1 = container_of(ctrl->handler, struct rj54n1, hdl);
+       struct v4l2_subdev *sd = &rj54n1->subdev;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int data;
+
+       switch (ctrl->id) {
+       case V4L2_CID_VFLIP:
+               if (ctrl->val)
+                       data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 0, 1);
+               else
+                       data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 1, 1);
+               if (data < 0)
+                       return -EIO;
+               return 0;
+       case V4L2_CID_HFLIP:
+               if (ctrl->val)
+                       data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 0, 2);
+               else
+                       data = reg_set(client, RJ54N1_MIRROR_STILL_MODE, 2, 2);
+               if (data < 0)
+                       return -EIO;
+               return 0;
+       case V4L2_CID_GAIN:
+               if (reg_write(client, RJ54N1_Y_GAIN, ctrl->val * 2) < 0)
+                       return -EIO;
+               return 0;
+       case V4L2_CID_AUTO_WHITE_BALANCE:
+               /* Auto WB area - whole image */
+               if (reg_set(client, RJ54N1_WB_SEL_WEIGHT_I, ctrl->val << 7,
+                           0x80) < 0)
+                       return -EIO;
+               rj54n1->auto_wb = ctrl->val;
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static const struct v4l2_ctrl_ops rj54n1_ctrl_ops = {
+       .s_ctrl = rj54n1_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops rj54n1_subdev_core_ops = {
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .g_register     = rj54n1_g_register,
+       .s_register     = rj54n1_s_register,
+#endif
+       .s_power        = rj54n1_s_power,
+};
+
+static int rj54n1_g_mbus_config(struct v4l2_subdev *sd,
+                               struct v4l2_mbus_config *cfg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+
+       cfg->flags =
+               V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING |
+               V4L2_MBUS_MASTER | V4L2_MBUS_DATA_ACTIVE_HIGH |
+               V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_HIGH;
+       cfg->type = V4L2_MBUS_PARALLEL;
+       cfg->flags = soc_camera_apply_board_flags(ssdd, cfg);
+
+       return 0;
+}
+
+static int rj54n1_s_mbus_config(struct v4l2_subdev *sd,
+                               const struct v4l2_mbus_config *cfg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+
+       /* Figures 2.5-1 to 2.5-3 - default falling pixclk edge */
+       if (soc_camera_apply_board_flags(ssdd, cfg) &
+           V4L2_MBUS_PCLK_SAMPLE_RISING)
+               return reg_write(client, RJ54N1_OUT_SIGPO, 1 << 4);
+       else
+               return reg_write(client, RJ54N1_OUT_SIGPO, 0);
+}
+
+static const struct v4l2_subdev_video_ops rj54n1_subdev_video_ops = {
+       .s_stream       = rj54n1_s_stream,
+       .g_mbus_config  = rj54n1_g_mbus_config,
+       .s_mbus_config  = rj54n1_s_mbus_config,
+};
+
+static const struct v4l2_subdev_pad_ops rj54n1_subdev_pad_ops = {
+       .enum_mbus_code = rj54n1_enum_mbus_code,
+       .get_selection  = rj54n1_get_selection,
+       .set_selection  = rj54n1_set_selection,
+       .get_fmt        = rj54n1_get_fmt,
+       .set_fmt        = rj54n1_set_fmt,
+};
+
+static const struct v4l2_subdev_ops rj54n1_subdev_ops = {
+       .core   = &rj54n1_subdev_core_ops,
+       .video  = &rj54n1_subdev_video_ops,
+       .pad    = &rj54n1_subdev_pad_ops,
+};
+
+/*
+ * Interface active, can use i2c. If it fails, it can indeed mean, that
+ * this wasn't our capture interface, so, we wait for the right one
+ */
+static int rj54n1_video_probe(struct i2c_client *client,
+                             struct rj54n1_pdata *priv)
+{
+       struct rj54n1 *rj54n1 = to_rj54n1(client);
+       int data1, data2;
+       int ret;
+
+       ret = rj54n1_s_power(&rj54n1->subdev, 1);
+       if (ret < 0)
+               return ret;
+
+       /* Read out the chip version register */
+       data1 = reg_read(client, RJ54N1_DEV_CODE);
+       data2 = reg_read(client, RJ54N1_DEV_CODE2);
+
+       if (data1 != 0x51 || data2 != 0x10) {
+               ret = -ENODEV;
+               dev_info(&client->dev, "No RJ54N1CB0C found, read 0x%x:0x%x\n",
+                        data1, data2);
+               goto done;
+       }
+
+       /* Configure IOCTL polarity from the platform data: 0 or 1 << 7. */
+       ret = reg_write(client, RJ54N1_IOC, priv->ioctl_high << 7);
+       if (ret < 0)
+               goto done;
+
+       dev_info(&client->dev, "Detected a RJ54N1CB0C chip ID 0x%x:0x%x\n",
+                data1, data2);
+
+       ret = v4l2_ctrl_handler_setup(&rj54n1->hdl);
+
+done:
+       rj54n1_s_power(&rj54n1->subdev, 0);
+       return ret;
+}
+
+static int rj54n1_probe(struct i2c_client *client,
+                       const struct i2c_device_id *did)
+{
+       struct rj54n1 *rj54n1;
+       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+       struct rj54n1_pdata *rj54n1_priv;
+       int ret;
+
+       if (!ssdd || !ssdd->drv_priv) {
+               dev_err(&client->dev, "RJ54N1CB0C: missing platform data!\n");
+               return -EINVAL;
+       }
+
+       rj54n1_priv = ssdd->drv_priv;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+               dev_warn(&adapter->dev,
+                        "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE\n");
+               return -EIO;
+       }
+
+       rj54n1 = devm_kzalloc(&client->dev, sizeof(struct rj54n1), GFP_KERNEL);
+       if (!rj54n1)
+               return -ENOMEM;
+
+       v4l2_i2c_subdev_init(&rj54n1->subdev, client, &rj54n1_subdev_ops);
+       v4l2_ctrl_handler_init(&rj54n1->hdl, 4);
+       v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops,
+                       V4L2_CID_VFLIP, 0, 1, 1, 0);
+       v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops,
+                       V4L2_CID_HFLIP, 0, 1, 1, 0);
+       v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops,
+                       V4L2_CID_GAIN, 0, 127, 1, 66);
+       v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops,
+                       V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
+       rj54n1->subdev.ctrl_handler = &rj54n1->hdl;
+       if (rj54n1->hdl.error)
+               return rj54n1->hdl.error;
+
+       rj54n1->clk_div         = clk_div;
+       rj54n1->rect.left       = RJ54N1_COLUMN_SKIP;
+       rj54n1->rect.top        = RJ54N1_ROW_SKIP;
+       rj54n1->rect.width      = RJ54N1_MAX_WIDTH;
+       rj54n1->rect.height     = RJ54N1_MAX_HEIGHT;
+       rj54n1->width           = RJ54N1_MAX_WIDTH;
+       rj54n1->height          = RJ54N1_MAX_HEIGHT;
+       rj54n1->fmt             = &rj54n1_colour_fmts[0];
+       rj54n1->resize          = 1024;
+       rj54n1->tgclk_mhz       = (rj54n1_priv->mclk_freq / PLL_L * PLL_N) /
+               (clk_div.ratio_tg + 1) / (clk_div.ratio_t + 1);
+
+       rj54n1->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(rj54n1->clk)) {
+               ret = PTR_ERR(rj54n1->clk);
+               goto eclkget;
+       }
+
+       ret = rj54n1_video_probe(client, rj54n1_priv);
+       if (ret < 0) {
+               v4l2_clk_put(rj54n1->clk);
+eclkget:
+               v4l2_ctrl_handler_free(&rj54n1->hdl);
+       }
+
+       return ret;
+}
+
+static int rj54n1_remove(struct i2c_client *client)
+{
+       struct rj54n1 *rj54n1 = to_rj54n1(client);
+       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+
+       v4l2_clk_put(rj54n1->clk);
+       v4l2_device_unregister_subdev(&rj54n1->subdev);
+       if (ssdd->free_bus)
+               ssdd->free_bus(ssdd);
+       v4l2_ctrl_handler_free(&rj54n1->hdl);
+
+       return 0;
+}
+
+static const struct i2c_device_id rj54n1_id[] = {
+       { "rj54n1cb0c", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, rj54n1_id);
+
+static struct i2c_driver rj54n1_i2c_driver = {
+       .driver = {
+               .name = "rj54n1cb0c",
+       },
+       .probe          = rj54n1_probe,
+       .remove         = rj54n1_remove,
+       .id_table       = rj54n1_id,
+};
+
+module_i2c_driver(rj54n1_i2c_driver);
+
+MODULE_DESCRIPTION("Sharp RJ54N1CB0C Camera driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/soc_camera/soc_tw9910.c b/drivers/media/i2c/soc_camera/soc_tw9910.c
new file mode 100644 (file)
index 0000000..bdb5e0a
--- /dev/null
@@ -0,0 +1,999 @@
+/*
+ * tw9910 Video Driver
+ *
+ * Copyright (C) 2008 Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * Based on ov772x driver,
+ *
+ * Copyright (C) 2008 Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
+ * Copyright (C) 2008 Magnus Damm
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/videodev2.h>
+
+#include <media/soc_camera.h>
+#include <media/i2c/tw9910.h>
+#include <media/v4l2-clk.h>
+#include <media/v4l2-subdev.h>
+
+#define GET_ID(val)  ((val & 0xF8) >> 3)
+#define GET_REV(val) (val & 0x07)
+
+/*
+ * register offset
+ */
+#define ID             0x00 /* Product ID Code Register */
+#define STATUS1                0x01 /* Chip Status Register I */
+#define INFORM         0x02 /* Input Format */
+#define OPFORM         0x03 /* Output Format Control Register */
+#define DLYCTR         0x04 /* Hysteresis and HSYNC Delay Control */
+#define OUTCTR1                0x05 /* Output Control I */
+#define ACNTL1         0x06 /* Analog Control Register 1 */
+#define CROP_HI                0x07 /* Cropping Register, High */
+#define VDELAY_LO      0x08 /* Vertical Delay Register, Low */
+#define VACTIVE_LO     0x09 /* Vertical Active Register, Low */
+#define HDELAY_LO      0x0A /* Horizontal Delay Register, Low */
+#define HACTIVE_LO     0x0B /* Horizontal Active Register, Low */
+#define CNTRL1         0x0C /* Control Register I */
+#define VSCALE_LO      0x0D /* Vertical Scaling Register, Low */
+#define SCALE_HI       0x0E /* Scaling Register, High */
+#define HSCALE_LO      0x0F /* Horizontal Scaling Register, Low */
+#define BRIGHT         0x10 /* BRIGHTNESS Control Register */
+#define CONTRAST       0x11 /* CONTRAST Control Register */
+#define SHARPNESS      0x12 /* SHARPNESS Control Register I */
+#define SAT_U          0x13 /* Chroma (U) Gain Register */
+#define SAT_V          0x14 /* Chroma (V) Gain Register */
+#define HUE            0x15 /* Hue Control Register */
+#define CORING1                0x17
+#define CORING2                0x18 /* Coring and IF compensation */
+#define VBICNTL                0x19 /* VBI Control Register */
+#define ACNTL2         0x1A /* Analog Control 2 */
+#define OUTCTR2                0x1B /* Output Control 2 */
+#define SDT            0x1C /* Standard Selection */
+#define SDTR           0x1D /* Standard Recognition */
+#define TEST           0x1F /* Test Control Register */
+#define CLMPG          0x20 /* Clamping Gain */
+#define IAGC           0x21 /* Individual AGC Gain */
+#define AGCGAIN                0x22 /* AGC Gain */
+#define PEAKWT         0x23 /* White Peak Threshold */
+#define CLMPL          0x24 /* Clamp level */
+#define SYNCT          0x25 /* Sync Amplitude */
+#define MISSCNT                0x26 /* Sync Miss Count Register */
+#define PCLAMP         0x27 /* Clamp Position Register */
+#define VCNTL1         0x28 /* Vertical Control I */
+#define VCNTL2         0x29 /* Vertical Control II */
+#define CKILL          0x2A /* Color Killer Level Control */
+#define COMB           0x2B /* Comb Filter Control */
+#define LDLY           0x2C /* Luma Delay and H Filter Control */
+#define MISC1          0x2D /* Miscellaneous Control I */
+#define LOOP           0x2E /* LOOP Control Register */
+#define MISC2          0x2F /* Miscellaneous Control II */
+#define MVSN           0x30 /* Macrovision Detection */
+#define STATUS2                0x31 /* Chip STATUS II */
+#define HFREF          0x32 /* H monitor */
+#define CLMD           0x33 /* CLAMP MODE */
+#define IDCNTL         0x34 /* ID Detection Control */
+#define CLCNTL1                0x35 /* Clamp Control I */
+#define ANAPLLCTL      0x4C
+#define VBIMIN         0x4D
+#define HSLOWCTL       0x4E
+#define WSS3           0x4F
+#define FILLDATA       0x50
+#define SDID           0x51
+#define DID            0x52
+#define WSS1           0x53
+#define WSS2           0x54
+#define VVBI           0x55
+#define LCTL6          0x56
+#define LCTL7          0x57
+#define LCTL8          0x58
+#define LCTL9          0x59
+#define LCTL10         0x5A
+#define LCTL11         0x5B
+#define LCTL12         0x5C
+#define LCTL13         0x5D
+#define LCTL14         0x5E
+#define LCTL15         0x5F
+#define LCTL16         0x60
+#define LCTL17         0x61
+#define LCTL18         0x62
+#define LCTL19         0x63
+#define LCTL20         0x64
+#define LCTL21         0x65
+#define LCTL22         0x66
+#define LCTL23         0x67
+#define LCTL24         0x68
+#define LCTL25         0x69
+#define LCTL26         0x6A
+#define HSBEGIN                0x6B
+#define HSEND          0x6C
+#define OVSDLY         0x6D
+#define OVSEND         0x6E
+#define VBIDELAY       0x6F
+
+/*
+ * register detail
+ */
+
+/* INFORM */
+#define FC27_ON     0x40 /* 1 : Input crystal clock frequency is 27MHz */
+#define FC27_FF     0x00 /* 0 : Square pixel mode. */
+                        /*     Must use 24.54MHz for 60Hz field rate */
+                        /*     source or 29.5MHz for 50Hz field rate */
+#define IFSEL_S     0x10 /* 01 : S-video decoding */
+#define IFSEL_C     0x00 /* 00 : Composite video decoding */
+                        /* Y input video selection */
+#define YSEL_M0     0x00 /*  00 : Mux0 selected */
+#define YSEL_M1     0x04 /*  01 : Mux1 selected */
+#define YSEL_M2     0x08 /*  10 : Mux2 selected */
+#define YSEL_M3     0x10 /*  11 : Mux3 selected */
+
+/* OPFORM */
+#define MODE        0x80 /* 0 : CCIR601 compatible YCrCb 4:2:2 format */
+                        /* 1 : ITU-R-656 compatible data sequence format */
+#define LEN         0x40 /* 0 : 8-bit YCrCb 4:2:2 output format */
+                        /* 1 : 16-bit YCrCb 4:2:2 output format.*/
+#define LLCMODE     0x20 /* 1 : LLC output mode. */
+                        /* 0 : free-run output mode */
+#define AINC        0x10 /* Serial interface auto-indexing control */
+                        /* 0 : auto-increment */
+                        /* 1 : non-auto */
+#define VSCTL       0x08 /* 1 : Vertical out ctrl by DVALID */
+                        /* 0 : Vertical out ctrl by HACTIVE and DVALID */
+#define OEN_TRI_SEL_MASK       0x07
+#define OEN_TRI_SEL_ALL_ON     0x00 /* Enable output for Rev0/Rev1 */
+#define OEN_TRI_SEL_ALL_OFF_r0 0x06 /* All tri-stated for Rev0 */
+#define OEN_TRI_SEL_ALL_OFF_r1 0x07 /* All tri-stated for Rev1 */
+
+/* OUTCTR1 */
+#define VSP_LO      0x00 /* 0 : VS pin output polarity is active low */
+#define VSP_HI      0x80 /* 1 : VS pin output polarity is active high. */
+                        /* VS pin output control */
+#define VSSL_VSYNC  0x00 /*   0 : VSYNC  */
+#define VSSL_VACT   0x10 /*   1 : VACT   */
+#define VSSL_FIELD  0x20 /*   2 : FIELD  */
+#define VSSL_VVALID 0x30 /*   3 : VVALID */
+#define VSSL_ZERO   0x70 /*   7 : 0      */
+#define HSP_LOW     0x00 /* 0 : HS pin output polarity is active low */
+#define HSP_HI      0x08 /* 1 : HS pin output polarity is active high.*/
+                        /* HS pin output control */
+#define HSSL_HACT   0x00 /*   0 : HACT   */
+#define HSSL_HSYNC  0x01 /*   1 : HSYNC  */
+#define HSSL_DVALID 0x02 /*   2 : DVALID */
+#define HSSL_HLOCK  0x03 /*   3 : HLOCK  */
+#define HSSL_ASYNCW 0x04 /*   4 : ASYNCW */
+#define HSSL_ZERO   0x07 /*   7 : 0      */
+
+/* ACNTL1 */
+#define SRESET      0x80 /* resets the device to its default state
+                         * but all register content remain unchanged.
+                         * This bit is self-resetting.
+                         */
+#define ACNTL1_PDN_MASK        0x0e
+#define CLK_PDN                0x08 /* system clock power down */
+#define Y_PDN          0x04 /* Luma ADC power down */
+#define C_PDN          0x02 /* Chroma ADC power down */
+
+/* ACNTL2 */
+#define ACNTL2_PDN_MASK        0x40
+#define PLL_PDN                0x40 /* PLL power down */
+
+/* VBICNTL */
+
+/* RTSEL : control the real time signal output from the MPOUT pin */
+#define RTSEL_MASK  0x07
+#define RTSEL_VLOSS 0x00 /* 0000 = Video loss */
+#define RTSEL_HLOCK 0x01 /* 0001 = H-lock */
+#define RTSEL_SLOCK 0x02 /* 0010 = S-lock */
+#define RTSEL_VLOCK 0x03 /* 0011 = V-lock */
+#define RTSEL_MONO  0x04 /* 0100 = MONO */
+#define RTSEL_DET50 0x05 /* 0101 = DET50 */
+#define RTSEL_FIELD 0x06 /* 0110 = FIELD */
+#define RTSEL_RTCO  0x07 /* 0111 = RTCO ( Real Time Control ) */
+
+/* HSYNC start and end are constant for now */
+#define HSYNC_START    0x0260
+#define HSYNC_END      0x0300
+
+/*
+ * structure
+ */
+
+struct regval_list {
+       unsigned char reg_num;
+       unsigned char value;
+};
+
+struct tw9910_scale_ctrl {
+       char           *name;
+       unsigned short  width;
+       unsigned short  height;
+       u16             hscale;
+       u16             vscale;
+};
+
+struct tw9910_priv {
+       struct v4l2_subdev              subdev;
+       struct v4l2_clk                 *clk;
+       struct tw9910_video_info        *info;
+       const struct tw9910_scale_ctrl  *scale;
+       v4l2_std_id                     norm;
+       u32                             revision;
+};
+
+static const struct tw9910_scale_ctrl tw9910_ntsc_scales[] = {
+       {
+               .name   = "NTSC SQ",
+               .width  = 640,
+               .height = 480,
+               .hscale = 0x0100,
+               .vscale = 0x0100,
+       },
+       {
+               .name   = "NTSC CCIR601",
+               .width  = 720,
+               .height = 480,
+               .hscale = 0x0100,
+               .vscale = 0x0100,
+       },
+       {
+               .name   = "NTSC SQ (CIF)",
+               .width  = 320,
+               .height = 240,
+               .hscale = 0x0200,
+               .vscale = 0x0200,
+       },
+       {
+               .name   = "NTSC CCIR601 (CIF)",
+               .width  = 360,
+               .height = 240,
+               .hscale = 0x0200,
+               .vscale = 0x0200,
+       },
+       {
+               .name   = "NTSC SQ (QCIF)",
+               .width  = 160,
+               .height = 120,
+               .hscale = 0x0400,
+               .vscale = 0x0400,
+       },
+       {
+               .name   = "NTSC CCIR601 (QCIF)",
+               .width  = 180,
+               .height = 120,
+               .hscale = 0x0400,
+               .vscale = 0x0400,
+       },
+};
+
+static const struct tw9910_scale_ctrl tw9910_pal_scales[] = {
+       {
+               .name   = "PAL SQ",
+               .width  = 768,
+               .height = 576,
+               .hscale = 0x0100,
+               .vscale = 0x0100,
+       },
+       {
+               .name   = "PAL CCIR601",
+               .width  = 720,
+               .height = 576,
+               .hscale = 0x0100,
+               .vscale = 0x0100,
+       },
+       {
+               .name   = "PAL SQ (CIF)",
+               .width  = 384,
+               .height = 288,
+               .hscale = 0x0200,
+               .vscale = 0x0200,
+       },
+       {
+               .name   = "PAL CCIR601 (CIF)",
+               .width  = 360,
+               .height = 288,
+               .hscale = 0x0200,
+               .vscale = 0x0200,
+       },
+       {
+               .name   = "PAL SQ (QCIF)",
+               .width  = 192,
+               .height = 144,
+               .hscale = 0x0400,
+               .vscale = 0x0400,
+       },
+       {
+               .name   = "PAL CCIR601 (QCIF)",
+               .width  = 180,
+               .height = 144,
+               .hscale = 0x0400,
+               .vscale = 0x0400,
+       },
+};
+
+/*
+ * general function
+ */
+static struct tw9910_priv *to_tw9910(const struct i2c_client *client)
+{
+       return container_of(i2c_get_clientdata(client), struct tw9910_priv,
+                           subdev);
+}
+
+static int tw9910_mask_set(struct i2c_client *client, u8 command,
+                          u8 mask, u8 set)
+{
+       s32 val = i2c_smbus_read_byte_data(client, command);
+       if (val < 0)
+               return val;
+
+       val &= ~mask;
+       val |= set & mask;
+
+       return i2c_smbus_write_byte_data(client, command, val);
+}
+
+static int tw9910_set_scale(struct i2c_client *client,
+                           const struct tw9910_scale_ctrl *scale)
+{
+       int ret;
+
+       ret = i2c_smbus_write_byte_data(client, SCALE_HI,
+                                       (scale->vscale & 0x0F00) >> 4 |
+                                       (scale->hscale & 0x0F00) >> 8);
+       if (ret < 0)
+               return ret;
+
+       ret = i2c_smbus_write_byte_data(client, HSCALE_LO,
+                                       scale->hscale & 0x00FF);
+       if (ret < 0)
+               return ret;
+
+       ret = i2c_smbus_write_byte_data(client, VSCALE_LO,
+                                       scale->vscale & 0x00FF);
+
+       return ret;
+}
+
+static int tw9910_set_hsync(struct i2c_client *client)
+{
+       struct tw9910_priv *priv = to_tw9910(client);
+       int ret;
+
+       /* bit 10 - 3 */
+       ret = i2c_smbus_write_byte_data(client, HSBEGIN,
+                                       (HSYNC_START & 0x07F8) >> 3);
+       if (ret < 0)
+               return ret;
+
+       /* bit 10 - 3 */
+       ret = i2c_smbus_write_byte_data(client, HSEND,
+                                       (HSYNC_END & 0x07F8) >> 3);
+       if (ret < 0)
+               return ret;
+
+       /* So far only revisions 0 and 1 have been seen */
+       /* bit 2 - 0 */
+       if (1 == priv->revision)
+               ret = tw9910_mask_set(client, HSLOWCTL, 0x77,
+                                     (HSYNC_START & 0x0007) << 4 |
+                                     (HSYNC_END   & 0x0007));
+
+       return ret;
+}
+
+static void tw9910_reset(struct i2c_client *client)
+{
+       tw9910_mask_set(client, ACNTL1, SRESET, SRESET);
+       msleep(1);
+}
+
+static int tw9910_power(struct i2c_client *client, int enable)
+{
+       int ret;
+       u8 acntl1;
+       u8 acntl2;
+
+       if (enable) {
+               acntl1 = 0;
+               acntl2 = 0;
+       } else {
+               acntl1 = CLK_PDN | Y_PDN | C_PDN;
+               acntl2 = PLL_PDN;
+       }
+
+       ret = tw9910_mask_set(client, ACNTL1, ACNTL1_PDN_MASK, acntl1);
+       if (ret < 0)
+               return ret;
+
+       return tw9910_mask_set(client, ACNTL2, ACNTL2_PDN_MASK, acntl2);
+}
+
+static const struct tw9910_scale_ctrl *tw9910_select_norm(v4l2_std_id norm,
+                                                         u32 width, u32 height)
+{
+       const struct tw9910_scale_ctrl *scale;
+       const struct tw9910_scale_ctrl *ret = NULL;
+       __u32 diff = 0xffffffff, tmp;
+       int size, i;
+
+       if (norm & V4L2_STD_NTSC) {
+               scale = tw9910_ntsc_scales;
+               size = ARRAY_SIZE(tw9910_ntsc_scales);
+       } else if (norm & V4L2_STD_PAL) {
+               scale = tw9910_pal_scales;
+               size = ARRAY_SIZE(tw9910_pal_scales);
+       } else {
+               return NULL;
+       }
+
+       for (i = 0; i < size; i++) {
+               tmp = abs(width - scale[i].width) +
+                       abs(height - scale[i].height);
+               if (tmp < diff) {
+                       diff = tmp;
+                       ret = scale + i;
+               }
+       }
+
+       return ret;
+}
+
+/*
+ * subdevice operations
+ */
+static int tw9910_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct tw9910_priv *priv = to_tw9910(client);
+       u8 val;
+       int ret;
+
+       if (!enable) {
+               switch (priv->revision) {
+               case 0:
+                       val = OEN_TRI_SEL_ALL_OFF_r0;
+                       break;
+               case 1:
+                       val = OEN_TRI_SEL_ALL_OFF_r1;
+                       break;
+               default:
+                       dev_err(&client->dev, "un-supported revision\n");
+                       return -EINVAL;
+               }
+       } else {
+               val = OEN_TRI_SEL_ALL_ON;
+
+               if (!priv->scale) {
+                       dev_err(&client->dev, "norm select error\n");
+                       return -EPERM;
+               }
+
+               dev_dbg(&client->dev, "%s %dx%d\n",
+                       priv->scale->name,
+                       priv->scale->width,
+                       priv->scale->height);
+       }
+
+       ret = tw9910_mask_set(client, OPFORM, OEN_TRI_SEL_MASK, val);
+       if (ret < 0)
+               return ret;
+
+       return tw9910_power(client, enable);
+}
+
+static int tw9910_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct tw9910_priv *priv = to_tw9910(client);
+
+       *norm = priv->norm;
+
+       return 0;
+}
+
+static int tw9910_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct tw9910_priv *priv = to_tw9910(client);
+       const unsigned hact = 720;
+       const unsigned hdelay = 15;
+       unsigned vact;
+       unsigned vdelay;
+       int ret;
+
+       if (!(norm & (V4L2_STD_NTSC | V4L2_STD_PAL)))
+               return -EINVAL;
+
+       priv->norm = norm;
+       if (norm & V4L2_STD_525_60) {
+               vact = 240;
+               vdelay = 18;
+               ret = tw9910_mask_set(client, VVBI, 0x10, 0x10);
+       } else {
+               vact = 288;
+               vdelay = 24;
+               ret = tw9910_mask_set(client, VVBI, 0x10, 0x00);
+       }
+       if (!ret)
+               ret = i2c_smbus_write_byte_data(client, CROP_HI,
+                       ((vdelay >> 2) & 0xc0) |
+                       ((vact >> 4) & 0x30) |
+                       ((hdelay >> 6) & 0x0c) |
+                       ((hact >> 8) & 0x03));
+       if (!ret)
+               ret = i2c_smbus_write_byte_data(client, VDELAY_LO,
+                       vdelay & 0xff);
+       if (!ret)
+               ret = i2c_smbus_write_byte_data(client, VACTIVE_LO,
+                       vact & 0xff);
+
+       return ret;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int tw9910_g_register(struct v4l2_subdev *sd,
+                            struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret;
+
+       if (reg->reg > 0xff)
+               return -EINVAL;
+
+       reg->size = 1;
+       ret = i2c_smbus_read_byte_data(client, reg->reg);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * ret      = int
+        * reg->val = __u64
+        */
+       reg->val = (__u64)ret;
+
+       return 0;
+}
+
+static int tw9910_s_register(struct v4l2_subdev *sd,
+                            const struct v4l2_dbg_register *reg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (reg->reg > 0xff ||
+           reg->val > 0xff)
+               return -EINVAL;
+
+       return i2c_smbus_write_byte_data(client, reg->reg, reg->val);
+}
+#endif
+
+static int tw9910_s_power(struct v4l2_subdev *sd, int on)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       struct tw9910_priv *priv = to_tw9910(client);
+
+       return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
+}
+
+static int tw9910_set_frame(struct v4l2_subdev *sd, u32 *width, u32 *height)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct tw9910_priv *priv = to_tw9910(client);
+       int ret = -EINVAL;
+       u8 val;
+
+       /*
+        * select suitable norm
+        */
+       priv->scale = tw9910_select_norm(priv->norm, *width, *height);
+       if (!priv->scale)
+               goto tw9910_set_fmt_error;
+
+       /*
+        * reset hardware
+        */
+       tw9910_reset(client);
+
+       /*
+        * set bus width
+        */
+       val = 0x00;
+       if (SOCAM_DATAWIDTH_16 == priv->info->buswidth)
+               val = LEN;
+
+       ret = tw9910_mask_set(client, OPFORM, LEN, val);
+       if (ret < 0)
+               goto tw9910_set_fmt_error;
+
+       /*
+        * select MPOUT behavior
+        */
+       switch (priv->info->mpout) {
+       case TW9910_MPO_VLOSS:
+               val = RTSEL_VLOSS; break;
+       case TW9910_MPO_HLOCK:
+               val = RTSEL_HLOCK; break;
+       case TW9910_MPO_SLOCK:
+               val = RTSEL_SLOCK; break;
+       case TW9910_MPO_VLOCK:
+               val = RTSEL_VLOCK; break;
+       case TW9910_MPO_MONO:
+               val = RTSEL_MONO;  break;
+       case TW9910_MPO_DET50:
+               val = RTSEL_DET50; break;
+       case TW9910_MPO_FIELD:
+               val = RTSEL_FIELD; break;
+       case TW9910_MPO_RTCO:
+               val = RTSEL_RTCO;  break;
+       default:
+               val = 0;
+       }
+
+       ret = tw9910_mask_set(client, VBICNTL, RTSEL_MASK, val);
+       if (ret < 0)
+               goto tw9910_set_fmt_error;
+
+       /*
+        * set scale
+        */
+       ret = tw9910_set_scale(client, priv->scale);
+       if (ret < 0)
+               goto tw9910_set_fmt_error;
+
+       /*
+        * set hsync
+        */
+       ret = tw9910_set_hsync(client);
+       if (ret < 0)
+               goto tw9910_set_fmt_error;
+
+       *width = priv->scale->width;
+       *height = priv->scale->height;
+
+       return ret;
+
+tw9910_set_fmt_error:
+
+       tw9910_reset(client);
+       priv->scale = NULL;
+
+       return ret;
+}
+
+static int tw9910_get_selection(struct v4l2_subdev *sd,
+               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_selection *sel)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct tw9910_priv *priv = to_tw9910(client);
+
+       if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+               return -EINVAL;
+       /* Only CROP, CROP_DEFAULT and CROP_BOUNDS are supported */
+       if (sel->target > V4L2_SEL_TGT_CROP_BOUNDS)
+               return -EINVAL;
+
+       sel->r.left     = 0;
+       sel->r.top      = 0;
+       if (priv->norm & V4L2_STD_NTSC) {
+               sel->r.width    = 640;
+               sel->r.height   = 480;
+       } else {
+               sel->r.width    = 768;
+               sel->r.height   = 576;
+       }
+       return 0;
+}
+
+static int tw9910_get_fmt(struct v4l2_subdev *sd,
+               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_format *format)
+{
+       struct v4l2_mbus_framefmt *mf = &format->format;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct tw9910_priv *priv = to_tw9910(client);
+
+       if (format->pad)
+               return -EINVAL;
+
+       if (!priv->scale) {
+               priv->scale = tw9910_select_norm(priv->norm, 640, 480);
+               if (!priv->scale)
+                       return -EINVAL;
+       }
+
+       mf->width       = priv->scale->width;
+       mf->height      = priv->scale->height;
+       mf->code        = MEDIA_BUS_FMT_UYVY8_2X8;
+       mf->colorspace  = V4L2_COLORSPACE_SMPTE170M;
+       mf->field       = V4L2_FIELD_INTERLACED_BT;
+
+       return 0;
+}
+
+static int tw9910_s_fmt(struct v4l2_subdev *sd,
+                       struct v4l2_mbus_framefmt *mf)
+{
+       u32 width = mf->width, height = mf->height;
+       int ret;
+
+       WARN_ON(mf->field != V4L2_FIELD_ANY &&
+               mf->field != V4L2_FIELD_INTERLACED_BT);
+
+       /*
+        * check color format
+        */
+       if (mf->code != MEDIA_BUS_FMT_UYVY8_2X8)
+               return -EINVAL;
+
+       mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+       ret = tw9910_set_frame(sd, &width, &height);
+       if (!ret) {
+               mf->width       = width;
+               mf->height      = height;
+       }
+       return ret;
+}
+
+static int tw9910_set_fmt(struct v4l2_subdev *sd,
+               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_format *format)
+{
+       struct v4l2_mbus_framefmt *mf = &format->format;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct tw9910_priv *priv = to_tw9910(client);
+       const struct tw9910_scale_ctrl *scale;
+
+       if (format->pad)
+               return -EINVAL;
+
+       if (V4L2_FIELD_ANY == mf->field) {
+               mf->field = V4L2_FIELD_INTERLACED_BT;
+       } else if (V4L2_FIELD_INTERLACED_BT != mf->field) {
+               dev_err(&client->dev, "Field type %d invalid.\n", mf->field);
+               return -EINVAL;
+       }
+
+       mf->code = MEDIA_BUS_FMT_UYVY8_2X8;
+       mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+       /*
+        * select suitable norm
+        */
+       scale = tw9910_select_norm(priv->norm, mf->width, mf->height);
+       if (!scale)
+               return -EINVAL;
+
+       mf->width       = scale->width;
+       mf->height      = scale->height;
+
+       if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+               return tw9910_s_fmt(sd, mf);
+       cfg->try_fmt = *mf;
+       return 0;
+}
+
+static int tw9910_video_probe(struct i2c_client *client)
+{
+       struct tw9910_priv *priv = to_tw9910(client);
+       s32 id;
+       int ret;
+
+       /*
+        * tw9910 only use 8 or 16 bit bus width
+        */
+       if (SOCAM_DATAWIDTH_16 != priv->info->buswidth &&
+           SOCAM_DATAWIDTH_8  != priv->info->buswidth) {
+               dev_err(&client->dev, "bus width error\n");
+               return -ENODEV;
+       }
+
+       ret = tw9910_s_power(&priv->subdev, 1);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * check and show Product ID
+        * So far only revisions 0 and 1 have been seen
+        */
+       id = i2c_smbus_read_byte_data(client, ID);
+       priv->revision = GET_REV(id);
+       id = GET_ID(id);
+
+       if (0x0B != id ||
+           0x01 < priv->revision) {
+               dev_err(&client->dev,
+                       "Product ID error %x:%x\n",
+                       id, priv->revision);
+               ret = -ENODEV;
+               goto done;
+       }
+
+       dev_info(&client->dev,
+                "tw9910 Product ID %0x:%0x\n", id, priv->revision);
+
+       priv->norm = V4L2_STD_NTSC;
+       priv->scale = &tw9910_ntsc_scales[0];
+
+done:
+       tw9910_s_power(&priv->subdev, 0);
+       return ret;
+}
+
+static const struct v4l2_subdev_core_ops tw9910_subdev_core_ops = {
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .g_register     = tw9910_g_register,
+       .s_register     = tw9910_s_register,
+#endif
+       .s_power        = tw9910_s_power,
+};
+
+static int tw9910_enum_mbus_code(struct v4l2_subdev *sd,
+               struct v4l2_subdev_pad_config *cfg,
+               struct v4l2_subdev_mbus_code_enum *code)
+{
+       if (code->pad || code->index)
+               return -EINVAL;
+
+       code->code = MEDIA_BUS_FMT_UYVY8_2X8;
+       return 0;
+}
+
+static int tw9910_g_mbus_config(struct v4l2_subdev *sd,
+                               struct v4l2_mbus_config *cfg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+
+       cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
+               V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW |
+               V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW |
+               V4L2_MBUS_DATA_ACTIVE_HIGH;
+       cfg->type = V4L2_MBUS_PARALLEL;
+       cfg->flags = soc_camera_apply_board_flags(ssdd, cfg);
+
+       return 0;
+}
+
+static int tw9910_s_mbus_config(struct v4l2_subdev *sd,
+                               const struct v4l2_mbus_config *cfg)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
+       u8 val = VSSL_VVALID | HSSL_DVALID;
+       unsigned long flags = soc_camera_apply_board_flags(ssdd, cfg);
+
+       /*
+        * set OUTCTR1
+        *
+        * We use VVALID and DVALID signals to control VSYNC and HSYNC
+        * outputs, in this mode their polarity is inverted.
+        */
+       if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
+               val |= HSP_HI;
+
+       if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
+               val |= VSP_HI;
+
+       return i2c_smbus_write_byte_data(client, OUTCTR1, val);
+}
+
+static int tw9910_g_tvnorms(struct v4l2_subdev *sd, v4l2_std_id *norm)
+{
+       *norm = V4L2_STD_NTSC | V4L2_STD_PAL;
+       return 0;
+}
+
+static const struct v4l2_subdev_video_ops tw9910_subdev_video_ops = {
+       .s_std          = tw9910_s_std,
+       .g_std          = tw9910_g_std,
+       .s_stream       = tw9910_s_stream,
+       .g_mbus_config  = tw9910_g_mbus_config,
+       .s_mbus_config  = tw9910_s_mbus_config,
+       .g_tvnorms      = tw9910_g_tvnorms,
+};
+
+static const struct v4l2_subdev_pad_ops tw9910_subdev_pad_ops = {
+       .enum_mbus_code = tw9910_enum_mbus_code,
+       .get_selection  = tw9910_get_selection,
+       .get_fmt        = tw9910_get_fmt,
+       .set_fmt        = tw9910_set_fmt,
+};
+
+static const struct v4l2_subdev_ops tw9910_subdev_ops = {
+       .core   = &tw9910_subdev_core_ops,
+       .video  = &tw9910_subdev_video_ops,
+       .pad    = &tw9910_subdev_pad_ops,
+};
+
+/*
+ * i2c_driver function
+ */
+
+static int tw9910_probe(struct i2c_client *client,
+                       const struct i2c_device_id *did)
+
+{
+       struct tw9910_priv              *priv;
+       struct tw9910_video_info        *info;
+       struct i2c_adapter              *adapter =
+               to_i2c_adapter(client->dev.parent);
+       struct soc_camera_subdev_desc   *ssdd = soc_camera_i2c_to_desc(client);
+       int ret;
+
+       if (!ssdd || !ssdd->drv_priv) {
+               dev_err(&client->dev, "TW9910: missing platform data!\n");
+               return -EINVAL;
+       }
+
+       info = ssdd->drv_priv;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+               dev_err(&client->dev,
+                       "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE_DATA\n");
+               return -EIO;
+       }
+
+       priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->info   = info;
+
+       v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops);
+
+       priv->clk = v4l2_clk_get(&client->dev, "mclk");
+       if (IS_ERR(priv->clk))
+               return PTR_ERR(priv->clk);
+
+       ret = tw9910_video_probe(client);
+       if (ret < 0)
+               v4l2_clk_put(priv->clk);
+
+       return ret;
+}
+
+static int tw9910_remove(struct i2c_client *client)
+{
+       struct tw9910_priv *priv = to_tw9910(client);
+       v4l2_clk_put(priv->clk);
+       return 0;
+}
+
+static const struct i2c_device_id tw9910_id[] = {
+       { "tw9910", 0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, tw9910_id);
+
+static struct i2c_driver tw9910_i2c_driver = {
+       .driver = {
+               .name = "tw9910",
+       },
+       .probe    = tw9910_probe,
+       .remove   = tw9910_remove,
+       .id_table = tw9910_id,
+};
+
+module_i2c_driver(tw9910_i2c_driver);
+
+MODULE_DESCRIPTION("SoC Camera driver for tw9910");
+MODULE_AUTHOR("Kuninori Morimoto");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/soc_camera/tw9910.c b/drivers/media/i2c/soc_camera/tw9910.c
deleted file mode 100644 (file)
index bdb5e0a..0000000
+++ /dev/null
@@ -1,999 +0,0 @@
-/*
- * tw9910 Video Driver
- *
- * Copyright (C) 2008 Renesas Solutions Corp.
- * Kuninori Morimoto <morimoto.kuninori@renesas.com>
- *
- * Based on ov772x driver,
- *
- * Copyright (C) 2008 Kuninori Morimoto <morimoto.kuninori@renesas.com>
- * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
- * Copyright (C) 2008 Magnus Damm
- * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
- *
- * 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.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/v4l2-mediabus.h>
-#include <linux/videodev2.h>
-
-#include <media/soc_camera.h>
-#include <media/i2c/tw9910.h>
-#include <media/v4l2-clk.h>
-#include <media/v4l2-subdev.h>
-
-#define GET_ID(val)  ((val & 0xF8) >> 3)
-#define GET_REV(val) (val & 0x07)
-
-/*
- * register offset
- */
-#define ID             0x00 /* Product ID Code Register */
-#define STATUS1                0x01 /* Chip Status Register I */
-#define INFORM         0x02 /* Input Format */
-#define OPFORM         0x03 /* Output Format Control Register */
-#define DLYCTR         0x04 /* Hysteresis and HSYNC Delay Control */
-#define OUTCTR1                0x05 /* Output Control I */
-#define ACNTL1         0x06 /* Analog Control Register 1 */
-#define CROP_HI                0x07 /* Cropping Register, High */
-#define VDELAY_LO      0x08 /* Vertical Delay Register, Low */
-#define VACTIVE_LO     0x09 /* Vertical Active Register, Low */
-#define HDELAY_LO      0x0A /* Horizontal Delay Register, Low */
-#define HACTIVE_LO     0x0B /* Horizontal Active Register, Low */
-#define CNTRL1         0x0C /* Control Register I */
-#define VSCALE_LO      0x0D /* Vertical Scaling Register, Low */
-#define SCALE_HI       0x0E /* Scaling Register, High */
-#define HSCALE_LO      0x0F /* Horizontal Scaling Register, Low */
-#define BRIGHT         0x10 /* BRIGHTNESS Control Register */
-#define CONTRAST       0x11 /* CONTRAST Control Register */
-#define SHARPNESS      0x12 /* SHARPNESS Control Register I */
-#define SAT_U          0x13 /* Chroma (U) Gain Register */
-#define SAT_V          0x14 /* Chroma (V) Gain Register */
-#define HUE            0x15 /* Hue Control Register */
-#define CORING1                0x17
-#define CORING2                0x18 /* Coring and IF compensation */
-#define VBICNTL                0x19 /* VBI Control Register */
-#define ACNTL2         0x1A /* Analog Control 2 */
-#define OUTCTR2                0x1B /* Output Control 2 */
-#define SDT            0x1C /* Standard Selection */
-#define SDTR           0x1D /* Standard Recognition */
-#define TEST           0x1F /* Test Control Register */
-#define CLMPG          0x20 /* Clamping Gain */
-#define IAGC           0x21 /* Individual AGC Gain */
-#define AGCGAIN                0x22 /* AGC Gain */
-#define PEAKWT         0x23 /* White Peak Threshold */
-#define CLMPL          0x24 /* Clamp level */
-#define SYNCT          0x25 /* Sync Amplitude */
-#define MISSCNT                0x26 /* Sync Miss Count Register */
-#define PCLAMP         0x27 /* Clamp Position Register */
-#define VCNTL1         0x28 /* Vertical Control I */
-#define VCNTL2         0x29 /* Vertical Control II */
-#define CKILL          0x2A /* Color Killer Level Control */
-#define COMB           0x2B /* Comb Filter Control */
-#define LDLY           0x2C /* Luma Delay and H Filter Control */
-#define MISC1          0x2D /* Miscellaneous Control I */
-#define LOOP           0x2E /* LOOP Control Register */
-#define MISC2          0x2F /* Miscellaneous Control II */
-#define MVSN           0x30 /* Macrovision Detection */
-#define STATUS2                0x31 /* Chip STATUS II */
-#define HFREF          0x32 /* H monitor */
-#define CLMD           0x33 /* CLAMP MODE */
-#define IDCNTL         0x34 /* ID Detection Control */
-#define CLCNTL1                0x35 /* Clamp Control I */
-#define ANAPLLCTL      0x4C
-#define VBIMIN         0x4D
-#define HSLOWCTL       0x4E
-#define WSS3           0x4F
-#define FILLDATA       0x50
-#define SDID           0x51
-#define DID            0x52
-#define WSS1           0x53
-#define WSS2           0x54
-#define VVBI           0x55
-#define LCTL6          0x56
-#define LCTL7          0x57
-#define LCTL8          0x58
-#define LCTL9          0x59
-#define LCTL10         0x5A
-#define LCTL11         0x5B
-#define LCTL12         0x5C
-#define LCTL13         0x5D
-#define LCTL14         0x5E
-#define LCTL15         0x5F
-#define LCTL16         0x60
-#define LCTL17         0x61
-#define LCTL18         0x62
-#define LCTL19         0x63
-#define LCTL20         0x64
-#define LCTL21         0x65
-#define LCTL22         0x66
-#define LCTL23         0x67
-#define LCTL24         0x68
-#define LCTL25         0x69
-#define LCTL26         0x6A
-#define HSBEGIN                0x6B
-#define HSEND          0x6C
-#define OVSDLY         0x6D
-#define OVSEND         0x6E
-#define VBIDELAY       0x6F
-
-/*
- * register detail
- */
-
-/* INFORM */
-#define FC27_ON     0x40 /* 1 : Input crystal clock frequency is 27MHz */
-#define FC27_FF     0x00 /* 0 : Square pixel mode. */
-                        /*     Must use 24.54MHz for 60Hz field rate */
-                        /*     source or 29.5MHz for 50Hz field rate */
-#define IFSEL_S     0x10 /* 01 : S-video decoding */
-#define IFSEL_C     0x00 /* 00 : Composite video decoding */
-                        /* Y input video selection */
-#define YSEL_M0     0x00 /*  00 : Mux0 selected */
-#define YSEL_M1     0x04 /*  01 : Mux1 selected */
-#define YSEL_M2     0x08 /*  10 : Mux2 selected */
-#define YSEL_M3     0x10 /*  11 : Mux3 selected */
-
-/* OPFORM */
-#define MODE        0x80 /* 0 : CCIR601 compatible YCrCb 4:2:2 format */
-                        /* 1 : ITU-R-656 compatible data sequence format */
-#define LEN         0x40 /* 0 : 8-bit YCrCb 4:2:2 output format */
-                        /* 1 : 16-bit YCrCb 4:2:2 output format.*/
-#define LLCMODE     0x20 /* 1 : LLC output mode. */
-                        /* 0 : free-run output mode */
-#define AINC        0x10 /* Serial interface auto-indexing control */
-                        /* 0 : auto-increment */
-                        /* 1 : non-auto */
-#define VSCTL       0x08 /* 1 : Vertical out ctrl by DVALID */
-                        /* 0 : Vertical out ctrl by HACTIVE and DVALID */
-#define OEN_TRI_SEL_MASK       0x07
-#define OEN_TRI_SEL_ALL_ON     0x00 /* Enable output for Rev0/Rev1 */
-#define OEN_TRI_SEL_ALL_OFF_r0 0x06 /* All tri-stated for Rev0 */
-#define OEN_TRI_SEL_ALL_OFF_r1 0x07 /* All tri-stated for Rev1 */
-
-/* OUTCTR1 */
-#define VSP_LO      0x00 /* 0 : VS pin output polarity is active low */
-#define VSP_HI      0x80 /* 1 : VS pin output polarity is active high. */
-                        /* VS pin output control */
-#define VSSL_VSYNC  0x00 /*   0 : VSYNC  */
-#define VSSL_VACT   0x10 /*   1 : VACT   */
-#define VSSL_FIELD  0x20 /*   2 : FIELD  */
-#define VSSL_VVALID 0x30 /*   3 : VVALID */
-#define VSSL_ZERO   0x70 /*   7 : 0      */
-#define HSP_LOW     0x00 /* 0 : HS pin output polarity is active low */
-#define HSP_HI      0x08 /* 1 : HS pin output polarity is active high.*/
-                        /* HS pin output control */
-#define HSSL_HACT   0x00 /*   0 : HACT   */
-#define HSSL_HSYNC  0x01 /*   1 : HSYNC  */
-#define HSSL_DVALID 0x02 /*   2 : DVALID */
-#define HSSL_HLOCK  0x03 /*   3 : HLOCK  */
-#define HSSL_ASYNCW 0x04 /*   4 : ASYNCW */
-#define HSSL_ZERO   0x07 /*   7 : 0      */
-
-/* ACNTL1 */
-#define SRESET      0x80 /* resets the device to its default state
-                         * but all register content remain unchanged.
-                         * This bit is self-resetting.
-                         */
-#define ACNTL1_PDN_MASK        0x0e
-#define CLK_PDN                0x08 /* system clock power down */
-#define Y_PDN          0x04 /* Luma ADC power down */
-#define C_PDN          0x02 /* Chroma ADC power down */
-
-/* ACNTL2 */
-#define ACNTL2_PDN_MASK        0x40
-#define PLL_PDN                0x40 /* PLL power down */
-
-/* VBICNTL */
-
-/* RTSEL : control the real time signal output from the MPOUT pin */
-#define RTSEL_MASK  0x07
-#define RTSEL_VLOSS 0x00 /* 0000 = Video loss */
-#define RTSEL_HLOCK 0x01 /* 0001 = H-lock */
-#define RTSEL_SLOCK 0x02 /* 0010 = S-lock */
-#define RTSEL_VLOCK 0x03 /* 0011 = V-lock */
-#define RTSEL_MONO  0x04 /* 0100 = MONO */
-#define RTSEL_DET50 0x05 /* 0101 = DET50 */
-#define RTSEL_FIELD 0x06 /* 0110 = FIELD */
-#define RTSEL_RTCO  0x07 /* 0111 = RTCO ( Real Time Control ) */
-
-/* HSYNC start and end are constant for now */
-#define HSYNC_START    0x0260
-#define HSYNC_END      0x0300
-
-/*
- * structure
- */
-
-struct regval_list {
-       unsigned char reg_num;
-       unsigned char value;
-};
-
-struct tw9910_scale_ctrl {
-       char           *name;
-       unsigned short  width;
-       unsigned short  height;
-       u16             hscale;
-       u16             vscale;
-};
-
-struct tw9910_priv {
-       struct v4l2_subdev              subdev;
-       struct v4l2_clk                 *clk;
-       struct tw9910_video_info        *info;
-       const struct tw9910_scale_ctrl  *scale;
-       v4l2_std_id                     norm;
-       u32                             revision;
-};
-
-static const struct tw9910_scale_ctrl tw9910_ntsc_scales[] = {
-       {
-               .name   = "NTSC SQ",
-               .width  = 640,
-               .height = 480,
-               .hscale = 0x0100,
-               .vscale = 0x0100,
-       },
-       {
-               .name   = "NTSC CCIR601",
-               .width  = 720,
-               .height = 480,
-               .hscale = 0x0100,
-               .vscale = 0x0100,
-       },
-       {
-               .name   = "NTSC SQ (CIF)",
-               .width  = 320,
-               .height = 240,
-               .hscale = 0x0200,
-               .vscale = 0x0200,
-       },
-       {
-               .name   = "NTSC CCIR601 (CIF)",
-               .width  = 360,
-               .height = 240,
-               .hscale = 0x0200,
-               .vscale = 0x0200,
-       },
-       {
-               .name   = "NTSC SQ (QCIF)",
-               .width  = 160,
-               .height = 120,
-               .hscale = 0x0400,
-               .vscale = 0x0400,
-       },
-       {
-               .name   = "NTSC CCIR601 (QCIF)",
-               .width  = 180,
-               .height = 120,
-               .hscale = 0x0400,
-               .vscale = 0x0400,
-       },
-};
-
-static const struct tw9910_scale_ctrl tw9910_pal_scales[] = {
-       {
-               .name   = "PAL SQ",
-               .width  = 768,
-               .height = 576,
-               .hscale = 0x0100,
-               .vscale = 0x0100,
-       },
-       {
-               .name   = "PAL CCIR601",
-               .width  = 720,
-               .height = 576,
-               .hscale = 0x0100,
-               .vscale = 0x0100,
-       },
-       {
-               .name   = "PAL SQ (CIF)",
-               .width  = 384,
-               .height = 288,
-               .hscale = 0x0200,
-               .vscale = 0x0200,
-       },
-       {
-               .name   = "PAL CCIR601 (CIF)",
-               .width  = 360,
-               .height = 288,
-               .hscale = 0x0200,
-               .vscale = 0x0200,
-       },
-       {
-               .name   = "PAL SQ (QCIF)",
-               .width  = 192,
-               .height = 144,
-               .hscale = 0x0400,
-               .vscale = 0x0400,
-       },
-       {
-               .name   = "PAL CCIR601 (QCIF)",
-               .width  = 180,
-               .height = 144,
-               .hscale = 0x0400,
-               .vscale = 0x0400,
-       },
-};
-
-/*
- * general function
- */
-static struct tw9910_priv *to_tw9910(const struct i2c_client *client)
-{
-       return container_of(i2c_get_clientdata(client), struct tw9910_priv,
-                           subdev);
-}
-
-static int tw9910_mask_set(struct i2c_client *client, u8 command,
-                          u8 mask, u8 set)
-{
-       s32 val = i2c_smbus_read_byte_data(client, command);
-       if (val < 0)
-               return val;
-
-       val &= ~mask;
-       val |= set & mask;
-
-       return i2c_smbus_write_byte_data(client, command, val);
-}
-
-static int tw9910_set_scale(struct i2c_client *client,
-                           const struct tw9910_scale_ctrl *scale)
-{
-       int ret;
-
-       ret = i2c_smbus_write_byte_data(client, SCALE_HI,
-                                       (scale->vscale & 0x0F00) >> 4 |
-                                       (scale->hscale & 0x0F00) >> 8);
-       if (ret < 0)
-               return ret;
-
-       ret = i2c_smbus_write_byte_data(client, HSCALE_LO,
-                                       scale->hscale & 0x00FF);
-       if (ret < 0)
-               return ret;
-
-       ret = i2c_smbus_write_byte_data(client, VSCALE_LO,
-                                       scale->vscale & 0x00FF);
-
-       return ret;
-}
-
-static int tw9910_set_hsync(struct i2c_client *client)
-{
-       struct tw9910_priv *priv = to_tw9910(client);
-       int ret;
-
-       /* bit 10 - 3 */
-       ret = i2c_smbus_write_byte_data(client, HSBEGIN,
-                                       (HSYNC_START & 0x07F8) >> 3);
-       if (ret < 0)
-               return ret;
-
-       /* bit 10 - 3 */
-       ret = i2c_smbus_write_byte_data(client, HSEND,
-                                       (HSYNC_END & 0x07F8) >> 3);
-       if (ret < 0)
-               return ret;
-
-       /* So far only revisions 0 and 1 have been seen */
-       /* bit 2 - 0 */
-       if (1 == priv->revision)
-               ret = tw9910_mask_set(client, HSLOWCTL, 0x77,
-                                     (HSYNC_START & 0x0007) << 4 |
-                                     (HSYNC_END   & 0x0007));
-
-       return ret;
-}
-
-static void tw9910_reset(struct i2c_client *client)
-{
-       tw9910_mask_set(client, ACNTL1, SRESET, SRESET);
-       msleep(1);
-}
-
-static int tw9910_power(struct i2c_client *client, int enable)
-{
-       int ret;
-       u8 acntl1;
-       u8 acntl2;
-
-       if (enable) {
-               acntl1 = 0;
-               acntl2 = 0;
-       } else {
-               acntl1 = CLK_PDN | Y_PDN | C_PDN;
-               acntl2 = PLL_PDN;
-       }
-
-       ret = tw9910_mask_set(client, ACNTL1, ACNTL1_PDN_MASK, acntl1);
-       if (ret < 0)
-               return ret;
-
-       return tw9910_mask_set(client, ACNTL2, ACNTL2_PDN_MASK, acntl2);
-}
-
-static const struct tw9910_scale_ctrl *tw9910_select_norm(v4l2_std_id norm,
-                                                         u32 width, u32 height)
-{
-       const struct tw9910_scale_ctrl *scale;
-       const struct tw9910_scale_ctrl *ret = NULL;
-       __u32 diff = 0xffffffff, tmp;
-       int size, i;
-
-       if (norm & V4L2_STD_NTSC) {
-               scale = tw9910_ntsc_scales;
-               size = ARRAY_SIZE(tw9910_ntsc_scales);
-       } else if (norm & V4L2_STD_PAL) {
-               scale = tw9910_pal_scales;
-               size = ARRAY_SIZE(tw9910_pal_scales);
-       } else {
-               return NULL;
-       }
-
-       for (i = 0; i < size; i++) {
-               tmp = abs(width - scale[i].width) +
-                       abs(height - scale[i].height);
-               if (tmp < diff) {
-                       diff = tmp;
-                       ret = scale + i;
-               }
-       }
-
-       return ret;
-}
-
-/*
- * subdevice operations
- */
-static int tw9910_s_stream(struct v4l2_subdev *sd, int enable)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct tw9910_priv *priv = to_tw9910(client);
-       u8 val;
-       int ret;
-
-       if (!enable) {
-               switch (priv->revision) {
-               case 0:
-                       val = OEN_TRI_SEL_ALL_OFF_r0;
-                       break;
-               case 1:
-                       val = OEN_TRI_SEL_ALL_OFF_r1;
-                       break;
-               default:
-                       dev_err(&client->dev, "un-supported revision\n");
-                       return -EINVAL;
-               }
-       } else {
-               val = OEN_TRI_SEL_ALL_ON;
-
-               if (!priv->scale) {
-                       dev_err(&client->dev, "norm select error\n");
-                       return -EPERM;
-               }
-
-               dev_dbg(&client->dev, "%s %dx%d\n",
-                       priv->scale->name,
-                       priv->scale->width,
-                       priv->scale->height);
-       }
-
-       ret = tw9910_mask_set(client, OPFORM, OEN_TRI_SEL_MASK, val);
-       if (ret < 0)
-               return ret;
-
-       return tw9910_power(client, enable);
-}
-
-static int tw9910_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct tw9910_priv *priv = to_tw9910(client);
-
-       *norm = priv->norm;
-
-       return 0;
-}
-
-static int tw9910_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct tw9910_priv *priv = to_tw9910(client);
-       const unsigned hact = 720;
-       const unsigned hdelay = 15;
-       unsigned vact;
-       unsigned vdelay;
-       int ret;
-
-       if (!(norm & (V4L2_STD_NTSC | V4L2_STD_PAL)))
-               return -EINVAL;
-
-       priv->norm = norm;
-       if (norm & V4L2_STD_525_60) {
-               vact = 240;
-               vdelay = 18;
-               ret = tw9910_mask_set(client, VVBI, 0x10, 0x10);
-       } else {
-               vact = 288;
-               vdelay = 24;
-               ret = tw9910_mask_set(client, VVBI, 0x10, 0x00);
-       }
-       if (!ret)
-               ret = i2c_smbus_write_byte_data(client, CROP_HI,
-                       ((vdelay >> 2) & 0xc0) |
-                       ((vact >> 4) & 0x30) |
-                       ((hdelay >> 6) & 0x0c) |
-                       ((hact >> 8) & 0x03));
-       if (!ret)
-               ret = i2c_smbus_write_byte_data(client, VDELAY_LO,
-                       vdelay & 0xff);
-       if (!ret)
-               ret = i2c_smbus_write_byte_data(client, VACTIVE_LO,
-                       vact & 0xff);
-
-       return ret;
-}
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int tw9910_g_register(struct v4l2_subdev *sd,
-                            struct v4l2_dbg_register *reg)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret;
-
-       if (reg->reg > 0xff)
-               return -EINVAL;
-
-       reg->size = 1;
-       ret = i2c_smbus_read_byte_data(client, reg->reg);
-       if (ret < 0)
-               return ret;
-
-       /*
-        * ret      = int
-        * reg->val = __u64
-        */
-       reg->val = (__u64)ret;
-
-       return 0;
-}
-
-static int tw9910_s_register(struct v4l2_subdev *sd,
-                            const struct v4l2_dbg_register *reg)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (reg->reg > 0xff ||
-           reg->val > 0xff)
-               return -EINVAL;
-
-       return i2c_smbus_write_byte_data(client, reg->reg, reg->val);
-}
-#endif
-
-static int tw9910_s_power(struct v4l2_subdev *sd, int on)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
-       struct tw9910_priv *priv = to_tw9910(client);
-
-       return soc_camera_set_power(&client->dev, ssdd, priv->clk, on);
-}
-
-static int tw9910_set_frame(struct v4l2_subdev *sd, u32 *width, u32 *height)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct tw9910_priv *priv = to_tw9910(client);
-       int ret = -EINVAL;
-       u8 val;
-
-       /*
-        * select suitable norm
-        */
-       priv->scale = tw9910_select_norm(priv->norm, *width, *height);
-       if (!priv->scale)
-               goto tw9910_set_fmt_error;
-
-       /*
-        * reset hardware
-        */
-       tw9910_reset(client);
-
-       /*
-        * set bus width
-        */
-       val = 0x00;
-       if (SOCAM_DATAWIDTH_16 == priv->info->buswidth)
-               val = LEN;
-
-       ret = tw9910_mask_set(client, OPFORM, LEN, val);
-       if (ret < 0)
-               goto tw9910_set_fmt_error;
-
-       /*
-        * select MPOUT behavior
-        */
-       switch (priv->info->mpout) {
-       case TW9910_MPO_VLOSS:
-               val = RTSEL_VLOSS; break;
-       case TW9910_MPO_HLOCK:
-               val = RTSEL_HLOCK; break;
-       case TW9910_MPO_SLOCK:
-               val = RTSEL_SLOCK; break;
-       case TW9910_MPO_VLOCK:
-               val = RTSEL_VLOCK; break;
-       case TW9910_MPO_MONO:
-               val = RTSEL_MONO;  break;
-       case TW9910_MPO_DET50:
-               val = RTSEL_DET50; break;
-       case TW9910_MPO_FIELD:
-               val = RTSEL_FIELD; break;
-       case TW9910_MPO_RTCO:
-               val = RTSEL_RTCO;  break;
-       default:
-               val = 0;
-       }
-
-       ret = tw9910_mask_set(client, VBICNTL, RTSEL_MASK, val);
-       if (ret < 0)
-               goto tw9910_set_fmt_error;
-
-       /*
-        * set scale
-        */
-       ret = tw9910_set_scale(client, priv->scale);
-       if (ret < 0)
-               goto tw9910_set_fmt_error;
-
-       /*
-        * set hsync
-        */
-       ret = tw9910_set_hsync(client);
-       if (ret < 0)
-               goto tw9910_set_fmt_error;
-
-       *width = priv->scale->width;
-       *height = priv->scale->height;
-
-       return ret;
-
-tw9910_set_fmt_error:
-
-       tw9910_reset(client);
-       priv->scale = NULL;
-
-       return ret;
-}
-
-static int tw9910_get_selection(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_selection *sel)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct tw9910_priv *priv = to_tw9910(client);
-
-       if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
-               return -EINVAL;
-       /* Only CROP, CROP_DEFAULT and CROP_BOUNDS are supported */
-       if (sel->target > V4L2_SEL_TGT_CROP_BOUNDS)
-               return -EINVAL;
-
-       sel->r.left     = 0;
-       sel->r.top      = 0;
-       if (priv->norm & V4L2_STD_NTSC) {
-               sel->r.width    = 640;
-               sel->r.height   = 480;
-       } else {
-               sel->r.width    = 768;
-               sel->r.height   = 576;
-       }
-       return 0;
-}
-
-static int tw9910_get_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_format *format)
-{
-       struct v4l2_mbus_framefmt *mf = &format->format;
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct tw9910_priv *priv = to_tw9910(client);
-
-       if (format->pad)
-               return -EINVAL;
-
-       if (!priv->scale) {
-               priv->scale = tw9910_select_norm(priv->norm, 640, 480);
-               if (!priv->scale)
-                       return -EINVAL;
-       }
-
-       mf->width       = priv->scale->width;
-       mf->height      = priv->scale->height;
-       mf->code        = MEDIA_BUS_FMT_UYVY8_2X8;
-       mf->colorspace  = V4L2_COLORSPACE_SMPTE170M;
-       mf->field       = V4L2_FIELD_INTERLACED_BT;
-
-       return 0;
-}
-
-static int tw9910_s_fmt(struct v4l2_subdev *sd,
-                       struct v4l2_mbus_framefmt *mf)
-{
-       u32 width = mf->width, height = mf->height;
-       int ret;
-
-       WARN_ON(mf->field != V4L2_FIELD_ANY &&
-               mf->field != V4L2_FIELD_INTERLACED_BT);
-
-       /*
-        * check color format
-        */
-       if (mf->code != MEDIA_BUS_FMT_UYVY8_2X8)
-               return -EINVAL;
-
-       mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
-
-       ret = tw9910_set_frame(sd, &width, &height);
-       if (!ret) {
-               mf->width       = width;
-               mf->height      = height;
-       }
-       return ret;
-}
-
-static int tw9910_set_fmt(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_format *format)
-{
-       struct v4l2_mbus_framefmt *mf = &format->format;
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct tw9910_priv *priv = to_tw9910(client);
-       const struct tw9910_scale_ctrl *scale;
-
-       if (format->pad)
-               return -EINVAL;
-
-       if (V4L2_FIELD_ANY == mf->field) {
-               mf->field = V4L2_FIELD_INTERLACED_BT;
-       } else if (V4L2_FIELD_INTERLACED_BT != mf->field) {
-               dev_err(&client->dev, "Field type %d invalid.\n", mf->field);
-               return -EINVAL;
-       }
-
-       mf->code = MEDIA_BUS_FMT_UYVY8_2X8;
-       mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
-
-       /*
-        * select suitable norm
-        */
-       scale = tw9910_select_norm(priv->norm, mf->width, mf->height);
-       if (!scale)
-               return -EINVAL;
-
-       mf->width       = scale->width;
-       mf->height      = scale->height;
-
-       if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
-               return tw9910_s_fmt(sd, mf);
-       cfg->try_fmt = *mf;
-       return 0;
-}
-
-static int tw9910_video_probe(struct i2c_client *client)
-{
-       struct tw9910_priv *priv = to_tw9910(client);
-       s32 id;
-       int ret;
-
-       /*
-        * tw9910 only use 8 or 16 bit bus width
-        */
-       if (SOCAM_DATAWIDTH_16 != priv->info->buswidth &&
-           SOCAM_DATAWIDTH_8  != priv->info->buswidth) {
-               dev_err(&client->dev, "bus width error\n");
-               return -ENODEV;
-       }
-
-       ret = tw9910_s_power(&priv->subdev, 1);
-       if (ret < 0)
-               return ret;
-
-       /*
-        * check and show Product ID
-        * So far only revisions 0 and 1 have been seen
-        */
-       id = i2c_smbus_read_byte_data(client, ID);
-       priv->revision = GET_REV(id);
-       id = GET_ID(id);
-
-       if (0x0B != id ||
-           0x01 < priv->revision) {
-               dev_err(&client->dev,
-                       "Product ID error %x:%x\n",
-                       id, priv->revision);
-               ret = -ENODEV;
-               goto done;
-       }
-
-       dev_info(&client->dev,
-                "tw9910 Product ID %0x:%0x\n", id, priv->revision);
-
-       priv->norm = V4L2_STD_NTSC;
-       priv->scale = &tw9910_ntsc_scales[0];
-
-done:
-       tw9910_s_power(&priv->subdev, 0);
-       return ret;
-}
-
-static const struct v4l2_subdev_core_ops tw9910_subdev_core_ops = {
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       .g_register     = tw9910_g_register,
-       .s_register     = tw9910_s_register,
-#endif
-       .s_power        = tw9910_s_power,
-};
-
-static int tw9910_enum_mbus_code(struct v4l2_subdev *sd,
-               struct v4l2_subdev_pad_config *cfg,
-               struct v4l2_subdev_mbus_code_enum *code)
-{
-       if (code->pad || code->index)
-               return -EINVAL;
-
-       code->code = MEDIA_BUS_FMT_UYVY8_2X8;
-       return 0;
-}
-
-static int tw9910_g_mbus_config(struct v4l2_subdev *sd,
-                               struct v4l2_mbus_config *cfg)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
-
-       cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
-               V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW |
-               V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW |
-               V4L2_MBUS_DATA_ACTIVE_HIGH;
-       cfg->type = V4L2_MBUS_PARALLEL;
-       cfg->flags = soc_camera_apply_board_flags(ssdd, cfg);
-
-       return 0;
-}
-
-static int tw9910_s_mbus_config(struct v4l2_subdev *sd,
-                               const struct v4l2_mbus_config *cfg)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
-       u8 val = VSSL_VVALID | HSSL_DVALID;
-       unsigned long flags = soc_camera_apply_board_flags(ssdd, cfg);
-
-       /*
-        * set OUTCTR1
-        *
-        * We use VVALID and DVALID signals to control VSYNC and HSYNC
-        * outputs, in this mode their polarity is inverted.
-        */
-       if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
-               val |= HSP_HI;
-
-       if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
-               val |= VSP_HI;
-
-       return i2c_smbus_write_byte_data(client, OUTCTR1, val);
-}
-
-static int tw9910_g_tvnorms(struct v4l2_subdev *sd, v4l2_std_id *norm)
-{
-       *norm = V4L2_STD_NTSC | V4L2_STD_PAL;
-       return 0;
-}
-
-static const struct v4l2_subdev_video_ops tw9910_subdev_video_ops = {
-       .s_std          = tw9910_s_std,
-       .g_std          = tw9910_g_std,
-       .s_stream       = tw9910_s_stream,
-       .g_mbus_config  = tw9910_g_mbus_config,
-       .s_mbus_config  = tw9910_s_mbus_config,
-       .g_tvnorms      = tw9910_g_tvnorms,
-};
-
-static const struct v4l2_subdev_pad_ops tw9910_subdev_pad_ops = {
-       .enum_mbus_code = tw9910_enum_mbus_code,
-       .get_selection  = tw9910_get_selection,
-       .get_fmt        = tw9910_get_fmt,
-       .set_fmt        = tw9910_set_fmt,
-};
-
-static const struct v4l2_subdev_ops tw9910_subdev_ops = {
-       .core   = &tw9910_subdev_core_ops,
-       .video  = &tw9910_subdev_video_ops,
-       .pad    = &tw9910_subdev_pad_ops,
-};
-
-/*
- * i2c_driver function
- */
-
-static int tw9910_probe(struct i2c_client *client,
-                       const struct i2c_device_id *did)
-
-{
-       struct tw9910_priv              *priv;
-       struct tw9910_video_info        *info;
-       struct i2c_adapter              *adapter =
-               to_i2c_adapter(client->dev.parent);
-       struct soc_camera_subdev_desc   *ssdd = soc_camera_i2c_to_desc(client);
-       int ret;
-
-       if (!ssdd || !ssdd->drv_priv) {
-               dev_err(&client->dev, "TW9910: missing platform data!\n");
-               return -EINVAL;
-       }
-
-       info = ssdd->drv_priv;
-
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
-               dev_err(&client->dev,
-                       "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE_DATA\n");
-               return -EIO;
-       }
-
-       priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-
-       priv->info   = info;
-
-       v4l2_i2c_subdev_init(&priv->subdev, client, &tw9910_subdev_ops);
-
-       priv->clk = v4l2_clk_get(&client->dev, "mclk");
-       if (IS_ERR(priv->clk))
-               return PTR_ERR(priv->clk);
-
-       ret = tw9910_video_probe(client);
-       if (ret < 0)
-               v4l2_clk_put(priv->clk);
-
-       return ret;
-}
-
-static int tw9910_remove(struct i2c_client *client)
-{
-       struct tw9910_priv *priv = to_tw9910(client);
-       v4l2_clk_put(priv->clk);
-       return 0;
-}
-
-static const struct i2c_device_id tw9910_id[] = {
-       { "tw9910", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, tw9910_id);
-
-static struct i2c_driver tw9910_i2c_driver = {
-       .driver = {
-               .name = "tw9910",
-       },
-       .probe    = tw9910_probe,
-       .remove   = tw9910_remove,
-       .id_table = tw9910_id,
-};
-
-module_i2c_driver(tw9910_i2c_driver);
-
-MODULE_DESCRIPTION("SoC Camera driver for tw9910");
-MODULE_AUTHOR("Kuninori Morimoto");
-MODULE_LICENSE("GPL v2");