]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
media: staging: atomisp: Add driver prefix to Kconfig option and module names
authorSakari Ailus <sakari.ailus@linux.intel.com>
Mon, 11 Sep 2017 22:46:32 +0000 (00:46 +0200)
committerMauro Carvalho Chehab <mchehab@osg.samsung.com>
Fri, 27 Oct 2017 13:36:18 +0000 (15:36 +0200)
By adding the "atomisp-" prefix to module names (and "ATOMISP_" to Kconfig
options), the staging drivers for e.g. sensors are labelled as being
specific to atomisp, which they effectively are.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
24 files changed:
drivers/staging/media/atomisp/i2c/Kconfig
drivers/staging/media/atomisp/i2c/Makefile
drivers/staging/media/atomisp/i2c/ap1302.c [deleted file]
drivers/staging/media/atomisp/i2c/atomisp-ap1302.c [new file with mode: 0644]
drivers/staging/media/atomisp/i2c/atomisp-gc0310.c [new file with mode: 0644]
drivers/staging/media/atomisp/i2c/atomisp-gc2235.c [new file with mode: 0644]
drivers/staging/media/atomisp/i2c/atomisp-libmsrlisthelper.c [new file with mode: 0644]
drivers/staging/media/atomisp/i2c/atomisp-lm3554.c [new file with mode: 0644]
drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c [new file with mode: 0644]
drivers/staging/media/atomisp/i2c/atomisp-ov2680.c [new file with mode: 0644]
drivers/staging/media/atomisp/i2c/atomisp-ov2722.c [new file with mode: 0644]
drivers/staging/media/atomisp/i2c/gc0310.c [deleted file]
drivers/staging/media/atomisp/i2c/gc2235.c [deleted file]
drivers/staging/media/atomisp/i2c/imx/Kconfig
drivers/staging/media/atomisp/i2c/imx/Makefile
drivers/staging/media/atomisp/i2c/libmsrlisthelper.c [deleted file]
drivers/staging/media/atomisp/i2c/lm3554.c [deleted file]
drivers/staging/media/atomisp/i2c/mt9m114.c [deleted file]
drivers/staging/media/atomisp/i2c/ov2680.c [deleted file]
drivers/staging/media/atomisp/i2c/ov2722.c [deleted file]
drivers/staging/media/atomisp/i2c/ov5693/Kconfig
drivers/staging/media/atomisp/i2c/ov5693/Makefile
drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c [new file with mode: 0644]
drivers/staging/media/atomisp/i2c/ov5693/ov5693.c [deleted file]

index 57505b7a25ca3e7d87abeca2a81a26715b106c72..09b1a97ce56018f774c543175e67bcebdf4acc82 100644 (file)
@@ -5,7 +5,7 @@
 source "drivers/staging/media/atomisp/i2c/ov5693/Kconfig"
 source "drivers/staging/media/atomisp/i2c/imx/Kconfig"
 
-config VIDEO_OV2722
+config VIDEO_ATOMISP_OV2722
        tristate "OVT ov2722 sensor support"
        depends on I2C && VIDEO_V4L2
        ---help---
@@ -16,7 +16,7 @@ config VIDEO_OV2722
 
         It currently only works with the atomisp driver.
 
-config VIDEO_GC2235
+config VIDEO_ATOMISP_GC2235
        tristate "Galaxy gc2235 sensor support"
        depends on I2C && VIDEO_V4L2
        ---help---
@@ -27,7 +27,7 @@ config VIDEO_GC2235
 
         It currently only works with the atomisp driver.
 
-config VIDEO_OV8858
+config VIDEO_ATOMISP_OV8858
        tristate "Omnivision ov8858 sensor support"
        depends on I2C && VIDEO_V4L2 && VIDEO_ATOMISP
        ---help---
@@ -38,7 +38,7 @@ config VIDEO_OV8858
 
         It currently only works with the atomisp driver.
 
-config VIDEO_MSRLIST_HELPER
+config VIDEO_ATOMISP_MSRLIST_HELPER
        tristate "Helper library to load, parse and apply large register lists."
        depends on I2C
        ---help---
@@ -48,7 +48,7 @@ config VIDEO_MSRLIST_HELPER
         To compile this driver as a module, choose M here: the
         module will be called libmsrlisthelper.
 
-config VIDEO_MT9M114
+config VIDEO_ATOMISP_MT9M114
        tristate "Aptina mt9m114 sensor support"
        depends on I2C && VIDEO_V4L2
        ---help---
@@ -59,7 +59,7 @@ config VIDEO_MT9M114
 
         It currently only works with the atomisp driver.
 
-config VIDEO_AP1302
+config VIDEO_ATOMISP_AP1302
        tristate "AP1302 external ISP support"
        depends on I2C && VIDEO_V4L2
        select REGMAP_I2C
@@ -71,14 +71,14 @@ config VIDEO_AP1302
 
         It currently only works with the atomisp driver.
 
-config VIDEO_GC0310
+config VIDEO_ATOMISP_GC0310
        tristate "GC0310 sensor support"
        depends on I2C && VIDEO_V4L2
        ---help---
          This is a Video4Linux2 sensor-level driver for the Galaxycore
          GC0310 0.3MP sensor.
         
-config VIDEO_OV2680
+config VIDEO_ATOMISP_OV2680
        tristate "Omnivision OV2680 sensor support"
        depends on I2C && VIDEO_V4L2
        ---help---
@@ -93,7 +93,7 @@ config VIDEO_OV2680
 # Kconfig for flash drivers
 #
 
-config VIDEO_LM3554
+config VIDEO_ATOMISP_LM3554
        tristate "LM3554 flash light driver"
        depends on VIDEO_V4L2 && I2C
        ---help---
index be13fab921753f3ad4abeb67e1571b835654daca..3d27c75f5fc549fc8121fd4da3d26bd68eb05e5e 100644 (file)
@@ -2,22 +2,22 @@
 # Makefile for sensor drivers
 #
 
-obj-$(CONFIG_VIDEO_IMX)        += imx/
-obj-$(CONFIG_VIDEO_OV5693)     += ov5693/
-obj-$(CONFIG_VIDEO_MT9M114)    += mt9m114.o
-obj-$(CONFIG_VIDEO_GC2235)     += gc2235.o
-obj-$(CONFIG_VIDEO_OV2722)     += ov2722.o
-obj-$(CONFIG_VIDEO_OV2680)     += ov2680.o
-obj-$(CONFIG_VIDEO_GC0310)     += gc0310.o
+obj-$(CONFIG_VIDEO_ATOMISP_IMX)        += imx/
+obj-$(CONFIG_VIDEO_ATOMISP_OV5693)     += ov5693/
+obj-$(CONFIG_VIDEO_ATOMISP_MT9M114)    += atomisp-mt9m114.o
+obj-$(CONFIG_VIDEO_ATOMISP_GC2235)     += atomisp-gc2235.o
+obj-$(CONFIG_VIDEO_ATOMISP_OV2722)     += atomisp-ov2722.o
+obj-$(CONFIG_VIDEO_ATOMISP_OV2680)     += atomisp-ov2680.o
+obj-$(CONFIG_VIDEO_ATOMISP_GC0310)     += atomisp-gc0310.o
 
-obj-$(CONFIG_VIDEO_MSRLIST_HELPER) += libmsrlisthelper.o
+obj-$(CONFIG_VIDEO_ATOMISP_MSRLIST_HELPER) += atomisp-libmsrlisthelper.o
 
-obj-$(CONFIG_VIDEO_AP1302)     += ap1302.o
+obj-$(CONFIG_VIDEO_ATOMISP_AP1302)     += atomisp-ap1302.o
 
 # Makefile for flash drivers
 #
 
-obj-$(CONFIG_VIDEO_LM3554) += lm3554.o
+obj-$(CONFIG_VIDEO_ATOMISP_LM3554) += atomisp-lm3554.o
 
 # HACK! While this driver is in bad shape, don't enable several warnings
 #       that would be otherwise enabled with W=1
diff --git a/drivers/staging/media/atomisp/i2c/ap1302.c b/drivers/staging/media/atomisp/i2c/ap1302.c
deleted file mode 100644 (file)
index 2f772a0..0000000
+++ /dev/null
@@ -1,1255 +0,0 @@
-/*
- *
- * Copyright (c) 2013 Intel Corporation. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include "../include/linux/atomisp.h"
-#include <linux/delay.h>
-#include <linux/firmware.h>
-#include <linux/i2c.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-device.h>
-#include "ap1302.h"
-
-#define to_ap1302_device(sub_dev) \
-               container_of(sub_dev, struct ap1302_device, sd)
-
-/* Static definitions */
-static struct regmap_config ap1302_reg16_config = {
-       .reg_bits = 16,
-       .val_bits = 16,
-       .reg_format_endian = REGMAP_ENDIAN_BIG,
-       .val_format_endian = REGMAP_ENDIAN_BIG,
-};
-
-static struct regmap_config ap1302_reg32_config = {
-       .reg_bits = 16,
-       .val_bits = 32,
-       .reg_format_endian = REGMAP_ENDIAN_BIG,
-       .val_format_endian = REGMAP_ENDIAN_BIG,
-};
-
-static enum ap1302_contexts ap1302_cntx_mapping[] = {
-       CONTEXT_PREVIEW,        /* Invalid atomisp run mode */
-       CONTEXT_VIDEO,          /* ATOMISP_RUN_MODE_VIDEO */
-       CONTEXT_SNAPSHOT,       /* ATOMISP_RUN_MODE_STILL_CAPTURE */
-       CONTEXT_SNAPSHOT,       /* ATOMISP_RUN_MODE_CONTINUOUS_CAPTURE */
-       CONTEXT_PREVIEW,        /* ATOMISP_RUN_MODE_PREVIEW */
-};
-
-static struct ap1302_res_struct ap1302_preview_res[] = {
-       {
-               .width = 640,
-               .height = 480,
-               .fps = 30,
-       },
-       {
-               .width = 720,
-               .height = 480,
-               .fps = 30,
-       },
-       {
-               .width = 1280,
-               .height = 720,
-               .fps = 30,
-       },
-       {
-               .width = 1920,
-               .height = 1080,
-               .fps = 30,
-       }
-};
-
-static struct ap1302_res_struct ap1302_snapshot_res[] = {
-       {
-               .width = 640,
-               .height = 480,
-               .fps = 30,
-       },
-       {
-               .width = 720,
-               .height = 480,
-               .fps = 30,
-       },
-       {
-               .width = 1280,
-               .height = 720,
-               .fps = 30,
-       },
-       {
-               .width = 1920,
-               .height = 1080,
-               .fps = 30,
-       }
-};
-
-static struct ap1302_res_struct ap1302_video_res[] = {
-       {
-               .width = 640,
-               .height = 480,
-               .fps = 30,
-       },
-       {
-               .width = 720,
-               .height = 480,
-               .fps = 30,
-       },
-       {
-               .width = 1280,
-               .height = 720,
-               .fps = 30,
-       },
-       {
-               .width = 1920,
-               .height = 1080,
-               .fps = 30,
-       }
-};
-
-static enum ap1302_contexts stream_to_context[] = {
-       CONTEXT_SNAPSHOT,
-       CONTEXT_PREVIEW,
-       CONTEXT_PREVIEW,
-       CONTEXT_VIDEO
-};
-
-static u16 aux_stream_config[CONTEXT_NUM][CONTEXT_NUM] = {
-       {0, 0, 0},      /* Preview: No aux streams. */
-       {1, 0, 2},      /* Snapshot: 1 for postview. 2 for video */
-       {1, 0, 0},      /* Video: 1 for preview. */
-};
-
-static struct ap1302_context_info context_info[] = {
-       {CNTX_WIDTH, AP1302_REG16, "width"},
-       {CNTX_HEIGHT, AP1302_REG16, "height"},
-       {CNTX_ROI_X0, AP1302_REG16, "roi_x0"},
-       {CNTX_ROI_X1, AP1302_REG16, "roi_x1"},
-       {CNTX_ROI_Y0, AP1302_REG16, "roi_y0"},
-       {CNTX_ROI_Y1, AP1302_REG16, "roi_y1"},
-       {CNTX_ASPECT, AP1302_REG16, "aspect"},
-       {CNTX_LOCK, AP1302_REG16, "lock"},
-       {CNTX_ENABLE, AP1302_REG16, "enable"},
-       {CNTX_OUT_FMT, AP1302_REG16, "out_fmt"},
-       {CNTX_SENSOR_MODE, AP1302_REG16, "sensor_mode"},
-       {CNTX_MIPI_CTRL, AP1302_REG16, "mipi_ctrl"},
-       {CNTX_MIPI_II_CTRL, AP1302_REG16, "mipi_ii_ctrl"},
-       {CNTX_LINE_TIME, AP1302_REG32, "line_time"},
-       {CNTX_MAX_FPS, AP1302_REG16, "max_fps"},
-       {CNTX_AE_USG, AP1302_REG16, "ae_usg"},
-       {CNTX_AE_UPPER_ET, AP1302_REG32, "ae_upper_et"},
-       {CNTX_AE_MAX_ET, AP1302_REG32, "ae_max_et"},
-       {CNTX_SS, AP1302_REG16, "ss"},
-       {CNTX_S1_SENSOR_MODE, AP1302_REG16, "s1_sensor_mode"},
-       {CNTX_HINF_CTRL, AP1302_REG16, "hinf_ctrl"},
-};
-
-/* This array stores the description list for metadata.
-   The metadata contains exposure settings and face
-   detection results. */
-static u16 ap1302_ss_list[] = {
-       0xb01c, /* From 0x0186 with size 0x1C are exposure settings. */
-       0x0186,
-       0xb002, /* 0x71c0 is for F-number */
-       0x71c0,
-       0xb010, /* From 0x03dc with size 0x10 are face general infos. */
-       0x03dc,
-       0xb0a0, /* From 0x03e4 with size 0xa0 are face detail infos. */
-       0x03e4,
-       0xb020, /* From 0x0604 with size 0x20 are smile rate infos. */
-       0x0604,
-       0x0000
-};
-
-/* End of static definitions */
-
-static int ap1302_i2c_read_reg(struct v4l2_subdev *sd,
-                               u16 reg, u16 len, void *val)
-{
-       struct ap1302_device *dev = to_ap1302_device(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret;
-
-       if (len == AP1302_REG16)
-               ret = regmap_read(dev->regmap16, reg, val);
-       else if (len == AP1302_REG32)
-               ret = regmap_read(dev->regmap32, reg, val);
-       else
-               ret = -EINVAL;
-       if (ret) {
-               dev_dbg(&client->dev, "Read reg failed. reg=0x%04X\n", reg);
-               return ret;
-       }
-       if (len == AP1302_REG16)
-               dev_dbg(&client->dev, "read_reg[0x%04X] = 0x%04X\n",
-                       reg, *(u16 *)val);
-       else
-               dev_dbg(&client->dev, "read_reg[0x%04X] = 0x%08X\n",
-                       reg, *(u32 *)val);
-       return ret;
-}
-
-static int ap1302_i2c_write_reg(struct v4l2_subdev *sd,
-                               u16 reg, u16 len, u32 val)
-{
-       struct ap1302_device *dev = to_ap1302_device(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret;
-       if (len == AP1302_REG16)
-               ret = regmap_write(dev->regmap16, reg, val);
-       else if (len == AP1302_REG32)
-               ret = regmap_write(dev->regmap32, reg, val);
-       else
-               ret = -EINVAL;
-       if (ret) {
-               dev_dbg(&client->dev, "Write reg failed. reg=0x%04X\n", reg);
-               return ret;
-       }
-       if (len == AP1302_REG16)
-               dev_dbg(&client->dev, "write_reg[0x%04X] = 0x%04X\n",
-                       reg, (u16)val);
-       else
-               dev_dbg(&client->dev, "write_reg[0x%04X] = 0x%08X\n",
-                       reg, (u32)val);
-       return ret;
-}
-
-static u16
-ap1302_calculate_context_reg_addr(enum ap1302_contexts context, u16 offset)
-{
-       u16 reg_addr;
-       /* The register offset is defined according to preview/video registers.
-          Preview and video context have the same register definition.
-          But snapshot context does not have register S1_SENSOR_MODE.
-          When setting snapshot registers, if the offset exceeds
-          S1_SENSOR_MODE, the actual offset needs to minus 2. */
-       if (context == CONTEXT_SNAPSHOT) {
-               if (offset == CNTX_S1_SENSOR_MODE)
-                       return 0;
-               if (offset > CNTX_S1_SENSOR_MODE)
-                       offset -= 2;
-       }
-       if (context == CONTEXT_PREVIEW)
-               reg_addr = REG_PREVIEW_BASE + offset;
-       else if (context == CONTEXT_VIDEO)
-               reg_addr = REG_VIDEO_BASE + offset;
-       else
-               reg_addr = REG_SNAPSHOT_BASE + offset;
-       return reg_addr;
-}
-
-static int ap1302_read_context_reg(struct v4l2_subdev *sd,
-               enum ap1302_contexts context, u16 offset, u16 len)
-{
-       struct ap1302_device *dev = to_ap1302_device(sd);
-       u16 reg_addr = ap1302_calculate_context_reg_addr(context, offset);
-       if (reg_addr == 0)
-               return -EINVAL;
-       return ap1302_i2c_read_reg(sd, reg_addr, len,
-                           ((u8 *)&dev->cntx_config[context]) + offset);
-}
-
-static int ap1302_write_context_reg(struct v4l2_subdev *sd,
-               enum ap1302_contexts context, u16 offset, u16 len)
-{
-       struct ap1302_device *dev = to_ap1302_device(sd);
-       u16 reg_addr = ap1302_calculate_context_reg_addr(context, offset);
-       if (reg_addr == 0)
-               return -EINVAL;
-       return ap1302_i2c_write_reg(sd, reg_addr, len,
-                       *(u32 *)(((u8 *)&dev->cntx_config[context]) + offset));
-}
-
-static int ap1302_dump_context_reg(struct v4l2_subdev *sd,
-                                  enum ap1302_contexts context)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct ap1302_device *dev = to_ap1302_device(sd);
-       int i;
-       dev_dbg(&client->dev, "Dump registers for context[%d]:\n", context);
-       for (i = 0; i < ARRAY_SIZE(context_info); i++) {
-               struct ap1302_context_info *info = &context_info[i];
-               u8 *var = (u8 *)&dev->cntx_config[context] + info->offset;
-               /* Snapshot context does not have s1_sensor_mode register. */
-               if (context == CONTEXT_SNAPSHOT &&
-                       info->offset == CNTX_S1_SENSOR_MODE)
-                       continue;
-               ap1302_read_context_reg(sd, context, info->offset, info->len);
-               if (info->len == AP1302_REG16)
-                       dev_dbg(&client->dev, "context.%s = 0x%04X (%d)\n",
-                               info->name, *(u16 *)var, *(u16 *)var);
-               else
-                       dev_dbg(&client->dev, "context.%s = 0x%08X (%d)\n",
-                               info->name, *(u32 *)var, *(u32 *)var);
-       }
-       return 0;
-}
-
-static int ap1302_request_firmware(struct v4l2_subdev *sd)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct ap1302_device *dev = to_ap1302_device(sd);
-       int ret;
-       ret = request_firmware(&dev->fw, "ap1302_fw.bin", &client->dev);
-       if (ret)
-               dev_err(&client->dev,
-                       "ap1302_request_firmware failed. ret=%d\n", ret);
-       return ret;
-}
-
-/* When loading firmware, host writes firmware data from address 0x8000.
-   When the address reaches 0x9FFF, the next address should return to 0x8000.
-   This function handles this address window and load firmware data to AP1302.
-   win_pos indicates the offset within this window. Firmware loading procedure
-   may call this function several times. win_pos records the current position
-   that has been written to.*/
-static int ap1302_write_fw_window(struct v4l2_subdev *sd,
-                                 u16 *win_pos, const u8 *buf, u32 len)
-{
-       struct ap1302_device *dev = to_ap1302_device(sd);
-       int ret;
-       u32 pos;
-       u32 sub_len;
-       for (pos = 0; pos < len; pos += sub_len) {
-               if (len - pos < AP1302_FW_WINDOW_SIZE - *win_pos)
-                       sub_len = len - pos;
-               else
-                       sub_len = AP1302_FW_WINDOW_SIZE - *win_pos;
-               ret = regmap_raw_write(dev->regmap16,
-                                       *win_pos + AP1302_FW_WINDOW_OFFSET,
-                                       buf + pos, sub_len);
-               if (ret)
-                       return ret;
-               *win_pos += sub_len;
-               if (*win_pos >= AP1302_FW_WINDOW_SIZE)
-                       *win_pos = 0;
-       }
-       return 0;
-}
-
-static int ap1302_load_firmware(struct v4l2_subdev *sd)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct ap1302_device *dev = to_ap1302_device(sd);
-       const struct ap1302_firmware *fw;
-       const u8 *fw_data;
-       u16 reg_val = 0;
-       u16 win_pos = 0;
-       int ret;
-
-       dev_info(&client->dev, "Start to load firmware.\n");
-       if (!dev->fw) {
-               dev_err(&client->dev, "firmware not requested.\n");
-               return -EINVAL;
-       }
-       fw = (const struct ap1302_firmware *) dev->fw->data;
-       if (dev->fw->size != (sizeof(*fw) + fw->total_size)) {
-               dev_err(&client->dev, "firmware size does not match.\n");
-               return -EINVAL;
-       }
-       /* The fw binary contains a header of struct ap1302_firmware.
-          Following the header is the bootdata of AP1302.
-          The bootdata pointer can be referenced as &fw[1]. */
-       fw_data = (u8 *)&fw[1];
-
-       /* Clear crc register. */
-       ret = ap1302_i2c_write_reg(sd, REG_SIP_CRC, AP1302_REG16, 0xFFFF);
-       if (ret)
-               return ret;
-
-       /* Load FW data for PLL init stage. */
-       ret = ap1302_write_fw_window(sd, &win_pos, fw_data, fw->pll_init_size);
-       if (ret)
-               return ret;
-
-       /* Write 2 to bootdata_stage register to apply basic_init_hp
-          settings and enable PLL. */
-       ret = ap1302_i2c_write_reg(sd, REG_BOOTDATA_STAGE,
-                                  AP1302_REG16, 0x0002);
-       if (ret)
-               return ret;
-
-       /* Wait 1ms for PLL to lock. */
-       msleep(20);
-
-       /* Load the rest of bootdata content. */
-       ret = ap1302_write_fw_window(sd, &win_pos, fw_data + fw->pll_init_size,
-                                    fw->total_size - fw->pll_init_size);
-       if (ret)
-               return ret;
-
-       /* Check crc. */
-       ret = ap1302_i2c_read_reg(sd, REG_SIP_CRC, AP1302_REG16, &reg_val);
-       if (ret)
-               return ret;
-       if (reg_val != fw->crc) {
-               dev_err(&client->dev,
-                       "crc does not match. T:0x%04X F:0x%04X\n",
-                       fw->crc, reg_val);
-               return -EAGAIN;
-       }
-
-       /* Write 0xFFFF to bootdata_stage register to indicate AP1302 that
-          the whole bootdata content has been loaded. */
-       ret = ap1302_i2c_write_reg(sd, REG_BOOTDATA_STAGE,
-                                  AP1302_REG16, 0xFFFF);
-       if (ret)
-               return ret;
-       dev_info(&client->dev, "Load firmware successfully.\n");
-
-       return 0;
-}
-
-static int __ap1302_s_power(struct v4l2_subdev *sd, int on, int load_fw)
-{
-       struct ap1302_device *dev = to_ap1302_device(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret, i;
-       u16 ss_ptr;
-
-       dev_info(&client->dev, "ap1302_s_power is called.\n");
-       ret = dev->platform_data->power_ctrl(sd, on);
-       if (ret) {
-               dev_err(&client->dev,
-                       "ap1302_s_power error. on=%d ret=%d\n", on, ret);
-               return ret;
-       }
-       dev->power_on = on;
-       if (!on || !load_fw)
-               return 0;
-       /* Load firmware after power on. */
-       ret = ap1302_load_firmware(sd);
-       if (ret) {
-               dev_err(&client->dev,
-                       "ap1302_load_firmware failed. ret=%d\n", ret);
-               return ret;
-       }
-       ret = ap1302_i2c_read_reg(sd, REG_SS_HEAD_PT0, AP1302_REG16, &ss_ptr);
-       if (ret)
-               return ret;
-       for (i = 0; i < ARRAY_SIZE(ap1302_ss_list); i++) {
-               ret = ap1302_i2c_write_reg(sd, ss_ptr + i * 2,
-                       AP1302_REG16, ap1302_ss_list[i]);
-               if (ret)
-                       return ret;
-       }
-       return ret;
-}
-
-static int ap1302_s_power(struct v4l2_subdev *sd, int on)
-{
-       struct ap1302_device *dev = to_ap1302_device(sd);
-       int ret;
-
-       mutex_lock(&dev->input_lock);
-       ret = __ap1302_s_power(sd, on, 1);
-       dev->sys_activated = 0;
-       mutex_unlock(&dev->input_lock);
-
-       return ret;
-}
-
-static int ap1302_s_config(struct v4l2_subdev *sd, void *pdata)
-{
-       struct ap1302_device *dev = to_ap1302_device(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct camera_mipi_info *mipi_info;
-       u16 reg_val = 0;
-       int ret;
-
-       dev_info(&client->dev, "ap1302_s_config is called.\n");
-       if (pdata == NULL)
-               return -ENODEV;
-
-       dev->platform_data = pdata;
-
-       mutex_lock(&dev->input_lock);
-
-       if (dev->platform_data->platform_init) {
-               ret = dev->platform_data->platform_init(client);
-               if (ret)
-                       goto fail_power;
-       }
-
-       ret = __ap1302_s_power(sd, 1, 0);
-       if (ret)
-               goto fail_power;
-
-       /* Detect for AP1302 */
-       ret = ap1302_i2c_read_reg(sd, REG_CHIP_VERSION, AP1302_REG16, &reg_val);
-       if (ret || (reg_val != AP1302_CHIP_ID)) {
-               dev_err(&client->dev,
-                       "Chip version does no match. ret=%d ver=0x%04x\n",
-                       ret, reg_val);
-               goto fail_config;
-       }
-       dev_info(&client->dev, "AP1302 Chip ID is 0x%X\n", reg_val);
-
-       /* Detect revision for AP1302 */
-       ret = ap1302_i2c_read_reg(sd, REG_CHIP_REV, AP1302_REG16, &reg_val);
-       if (ret)
-               goto fail_config;
-       dev_info(&client->dev, "AP1302 Chip Rev is 0x%X\n", reg_val);
-       ret = dev->platform_data->csi_cfg(sd, 1);
-       if (ret)
-               goto fail_config;
-
-       mipi_info = v4l2_get_subdev_hostdata(sd);
-       if (!mipi_info)
-               goto fail_config;
-       dev->num_lanes = mipi_info->num_lanes;
-
-       ret = __ap1302_s_power(sd, 0, 0);
-       if (ret)
-               goto fail_power;
-
-       mutex_unlock(&dev->input_lock);
-
-       return ret;
-
-fail_config:
-       __ap1302_s_power(sd, 0, 0);
-fail_power:
-       mutex_unlock(&dev->input_lock);
-       dev_err(&client->dev, "ap1302_s_config failed\n");
-       return ret;
-}
-
-static enum ap1302_contexts ap1302_get_context(struct v4l2_subdev *sd)
-{
-       struct ap1302_device *dev = to_ap1302_device(sd);
-       return dev->cur_context;
-}
-
-static int ap1302_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
-                                struct v4l2_subdev_mbus_code_enum *code)
-{
-       if (code->index)
-               return -EINVAL;
-
-       code->code = MEDIA_BUS_FMT_UYVY8_1X16;
-
-       return 0;
-}
-
-static int ap1302_match_resolution(struct ap1302_context_res *res,
-                                  struct v4l2_mbus_framefmt *fmt)
-{
-       s32 w0, h0, mismatch, distance;
-       s32 w1 = fmt->width;
-       s32 h1 = fmt->height;
-       s32 min_distance = INT_MAX;
-       s32 i, idx = -1;
-
-       if (w1 == 0 || h1 == 0)
-               return -1;
-
-       for (i = 0; i < res->res_num; i++) {
-               w0 = res->res_table[i].width;
-               h0 = res->res_table[i].height;
-               if (w0 < w1 || h0 < h1)
-                       continue;
-               mismatch = abs(w0 * h1 - w1 * h0) * 8192 / w1 / h0;
-               if (mismatch > 8192 * AP1302_MAX_RATIO_MISMATCH / 100)
-                       continue;
-               distance = (w0 * h1 + w1 * h0) * 8192 / w1 / h1;
-               if (distance < min_distance) {
-                       min_distance = distance;
-                       idx = i;
-               }
-       }
-
-       return idx;
-}
-
-static s32 ap1302_try_mbus_fmt_locked(struct v4l2_subdev *sd,
-                               enum ap1302_contexts context,
-                               struct v4l2_mbus_framefmt *fmt)
-{
-       struct ap1302_device *dev = to_ap1302_device(sd);
-       struct ap1302_res_struct *res_table;
-       s32 res_num, idx = -1;
-
-       res_table = dev->cntx_res[context].res_table;
-       res_num = dev->cntx_res[context].res_num;
-
-       if ((fmt->width <= res_table[res_num - 1].width) &&
-               (fmt->height <= res_table[res_num - 1].height))
-               idx = ap1302_match_resolution(&dev->cntx_res[context], fmt);
-       if (idx == -1)
-               idx = res_num - 1;
-
-       fmt->width = res_table[idx].width;
-       fmt->height = res_table[idx].height;
-       fmt->code = MEDIA_BUS_FMT_UYVY8_1X16;
-       return idx;
-}
-
-
-static int ap1302_get_fmt(struct v4l2_subdev *sd,
-                        struct v4l2_subdev_pad_config *cfg,
-                                        struct v4l2_subdev_format *format)
-
-{
-    struct v4l2_mbus_framefmt *fmt = &format->format;
-    struct ap1302_device *dev = to_ap1302_device(sd);
-       enum ap1302_contexts context;
-       struct ap1302_res_struct *res_table;
-       s32 cur_res;
-     if (format->pad)
-               return -EINVAL;
-       mutex_lock(&dev->input_lock);
-       context = ap1302_get_context(sd);
-       res_table = dev->cntx_res[context].res_table;
-       cur_res = dev->cntx_res[context].cur_res;
-       fmt->code = MEDIA_BUS_FMT_UYVY8_1X16;
-       fmt->width = res_table[cur_res].width;
-       fmt->height = res_table[cur_res].height;
-       mutex_unlock(&dev->input_lock);
-       return 0;
-}
-
-static int ap1302_set_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
-                         struct v4l2_subdev_format *format)
-{
-       struct v4l2_mbus_framefmt *fmt = &format->format;
-       struct ap1302_device *dev = to_ap1302_device(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct atomisp_input_stream_info *stream_info =
-               (struct atomisp_input_stream_info *)fmt->reserved;
-       enum ap1302_contexts context, main_context;
-       if (format->pad)
-               return -EINVAL;
-       if (!fmt)
-               return -EINVAL;
-       mutex_lock(&dev->input_lock);
-       if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
-               context = ap1302_get_context(sd);
-               ap1302_try_mbus_fmt_locked(sd, context, fmt);
-               cfg->try_fmt = *fmt;
-           mutex_unlock(&dev->input_lock);
-               return 0;
-               }
-       context = stream_to_context[stream_info->stream];
-       dev_dbg(&client->dev, "ap1302_set_mbus_fmt. stream=%d context=%d\n",
-               stream_info->stream, context);
-       dev->cntx_res[context].cur_res =
-               ap1302_try_mbus_fmt_locked(sd, context, fmt);
-       dev->cntx_config[context].width = fmt->width;
-       dev->cntx_config[context].height = fmt->height;
-       ap1302_write_context_reg(sd, context, CNTX_WIDTH, AP1302_REG16);
-       ap1302_write_context_reg(sd, context, CNTX_HEIGHT, AP1302_REG16);
-       ap1302_read_context_reg(sd, context, CNTX_OUT_FMT, AP1302_REG16);
-       dev->cntx_config[context].out_fmt &= ~OUT_FMT_TYPE_MASK;
-       dev->cntx_config[context].out_fmt |= AP1302_FMT_UYVY422;
-       ap1302_write_context_reg(sd, context, CNTX_OUT_FMT, AP1302_REG16);
-
-       main_context = ap1302_get_context(sd);
-       if (context == main_context) {
-               ap1302_read_context_reg(sd, context,
-                       CNTX_MIPI_CTRL, AP1302_REG16);
-               dev->cntx_config[context].mipi_ctrl &= ~MIPI_CTRL_IMGVC_MASK;
-               dev->cntx_config[context].mipi_ctrl |=
-                       (context << MIPI_CTRL_IMGVC_OFFSET);
-               dev->cntx_config[context].mipi_ctrl &= ~MIPI_CTRL_SSVC_MASK;
-               dev->cntx_config[context].mipi_ctrl |=
-                       (context << MIPI_CTRL_SSVC_OFFSET);
-               dev->cntx_config[context].mipi_ctrl &= ~MIPI_CTRL_SSTYPE_MASK;
-               dev->cntx_config[context].mipi_ctrl |=
-                       (0x12 << MIPI_CTRL_SSTYPE_OFFSET);
-               ap1302_write_context_reg(sd, context,
-                       CNTX_MIPI_CTRL, AP1302_REG16);
-               ap1302_read_context_reg(sd, context,
-                       CNTX_SS, AP1302_REG16);
-               dev->cntx_config[context].ss = AP1302_SS_CTRL;
-               ap1302_write_context_reg(sd, context,
-                       CNTX_SS, AP1302_REG16);
-       } else {
-               /* Configure aux stream */
-               ap1302_read_context_reg(sd, context,
-                       CNTX_MIPI_II_CTRL, AP1302_REG16);
-               dev->cntx_config[context].mipi_ii_ctrl &= ~MIPI_CTRL_IMGVC_MASK;
-               dev->cntx_config[context].mipi_ii_ctrl |=
-                       (context << MIPI_CTRL_IMGVC_OFFSET);
-               ap1302_write_context_reg(sd, context,
-                       CNTX_MIPI_II_CTRL, AP1302_REG16);
-               if (stream_info->enable) {
-                       ap1302_read_context_reg(sd, main_context,
-                               CNTX_OUT_FMT, AP1302_REG16);
-                       dev->cntx_config[context].out_fmt |=
-                               (aux_stream_config[main_context][context]
-                                << OUT_FMT_IIS_OFFSET);
-                       ap1302_write_context_reg(sd, main_context,
-                               CNTX_OUT_FMT, AP1302_REG16);
-               }
-       }
-       stream_info->ch_id = context;
-       mutex_unlock(&dev->input_lock);
-
-       return 0;
-}
-
-
-static int ap1302_g_frame_interval(struct v4l2_subdev *sd,
-                       struct v4l2_subdev_frame_interval *interval)
-{
-       struct ap1302_device *dev = to_ap1302_device(sd);
-       enum ap1302_contexts context;
-       struct ap1302_res_struct *res_table;
-       u32 cur_res;
-
-       mutex_lock(&dev->input_lock);
-       context = ap1302_get_context(sd);
-       res_table = dev->cntx_res[context].res_table;
-       cur_res = dev->cntx_res[context].cur_res;
-       interval->interval.denominator = res_table[cur_res].fps;
-       interval->interval.numerator = 1;
-       mutex_unlock(&dev->input_lock);
-       return 0;
-}
-
-static int ap1302_enum_frame_size(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
-                                 struct v4l2_subdev_frame_size_enum *fse)
-{
-       struct ap1302_device *dev = to_ap1302_device(sd);
-       enum ap1302_contexts context;
-       struct ap1302_res_struct *res_table;
-       int index = fse->index;
-
-       mutex_lock(&dev->input_lock);
-       context = ap1302_get_context(sd);
-       if (index >= dev->cntx_res[context].res_num) {
-               mutex_unlock(&dev->input_lock);
-               return -EINVAL;
-       }
-
-       res_table = dev->cntx_res[context].res_table;
-       fse->min_width = res_table[index].width;
-       fse->min_height = res_table[index].height;
-       fse->max_width = res_table[index].width;
-       fse->max_height = res_table[index].height;
-       mutex_unlock(&dev->input_lock);
-
-       return 0;
-}
-
-
-static int ap1302_g_skip_frames(struct v4l2_subdev *sd, u32 *frames)
-{
-       *frames = 0;
-       return 0;
-}
-
-static int ap1302_s_stream(struct v4l2_subdev *sd, int enable)
-{
-       struct ap1302_device *dev = to_ap1302_device(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       enum ap1302_contexts context;
-       u32 reg_val;
-       int ret;
-
-       mutex_lock(&dev->input_lock);
-       context = ap1302_get_context(sd);
-       dev_dbg(&client->dev, "ap1302_s_stream. context=%d enable=%d\n",
-                       context, enable);
-       /* Switch context */
-       ap1302_i2c_read_reg(sd, REG_CTRL,
-                           AP1302_REG16, &reg_val);
-       reg_val &= ~CTRL_CNTX_MASK;
-       reg_val |= (context<<CTRL_CNTX_OFFSET);
-       ap1302_i2c_write_reg(sd, REG_CTRL,
-                           AP1302_REG16, reg_val);
-       /* Select sensor */
-       ap1302_i2c_read_reg(sd, REG_SENSOR_SELECT,
-                           AP1302_REG16, &reg_val);
-       reg_val &= ~SENSOR_SELECT_MASK;
-       reg_val |= (AP1302_SENSOR_PRI<<SENSOR_SELECT_OFFSET);
-       ap1302_i2c_write_reg(sd, REG_SENSOR_SELECT,
-                           AP1302_REG16, reg_val);
-       if (enable) {
-               dev_info(&client->dev, "Start stream. context=%d\n", context);
-               ap1302_dump_context_reg(sd, context);
-               if (!dev->sys_activated) {
-                       reg_val = AP1302_SYS_ACTIVATE;
-                       dev->sys_activated = 1;
-               } else {
-                       reg_val = AP1302_SYS_SWITCH;
-               }
-       } else {
-               dev_info(&client->dev, "Stop stream. context=%d\n", context);
-               reg_val = AP1302_SYS_SWITCH;
-       }
-       ret = ap1302_i2c_write_reg(sd, REG_SYS_START, AP1302_REG16, reg_val);
-       if (ret)
-               dev_err(&client->dev,
-                       "AP1302 set stream failed. enable=%d\n", enable);
-       mutex_unlock(&dev->input_lock);
-       return ret;
-}
-
-static u16 ap1302_ev_values[] = {0xfd00, 0xfe80, 0x0, 0x180, 0x300};
-
-static int ap1302_set_exposure_off(struct v4l2_subdev *sd, s32 val)
-{
-       val -= AP1302_MIN_EV;
-       return ap1302_i2c_write_reg(sd, REG_AE_BV_OFF, AP1302_REG16,
-                               ap1302_ev_values[val]);
-}
-
-static u16 ap1302_wb_values[] = {
-       0, /* V4L2_WHITE_BALANCE_MANUAL */
-       0xf, /* V4L2_WHITE_BALANCE_AUTO */
-       0x2, /* V4L2_WHITE_BALANCE_INCANDESCENT */
-       0x4, /* V4L2_WHITE_BALANCE_FLUORESCENT */
-       0x5, /* V4L2_WHITE_BALANCE_FLUORESCENT_H */
-       0x1, /* V4L2_WHITE_BALANCE_HORIZON */
-       0x5, /* V4L2_WHITE_BALANCE_DAYLIGHT */
-       0xf, /* V4L2_WHITE_BALANCE_FLASH */
-       0x6, /* V4L2_WHITE_BALANCE_CLOUDY */
-       0x6, /* V4L2_WHITE_BALANCE_SHADE */
-};
-
-static int ap1302_set_wb_mode(struct v4l2_subdev *sd, s32 val)
-{
-       int ret = 0;
-       u16 reg_val;
-
-       ret = ap1302_i2c_read_reg(sd, REG_AWB_CTRL, AP1302_REG16, &reg_val);
-       if (ret)
-               return ret;
-       reg_val &= ~AWB_CTRL_MODE_MASK;
-       reg_val |= ap1302_wb_values[val] << AWB_CTRL_MODE_OFFSET;
-       if (val == V4L2_WHITE_BALANCE_FLASH)
-               reg_val |= AWB_CTRL_FLASH_MASK;
-       else
-               reg_val &= ~AWB_CTRL_FLASH_MASK;
-       ret = ap1302_i2c_write_reg(sd, REG_AWB_CTRL, AP1302_REG16, reg_val);
-       return ret;
-}
-
-static int ap1302_set_zoom(struct v4l2_subdev *sd, s32 val)
-{
-       ap1302_i2c_write_reg(sd, REG_DZ_TGT_FCT, AP1302_REG16,
-               val * 4 + 0x100);
-       return 0;
-}
-
-static u16 ap1302_sfx_values[] = {
-       0x00, /* V4L2_COLORFX_NONE */
-       0x03, /* V4L2_COLORFX_BW */
-       0x0d, /* V4L2_COLORFX_SEPIA */
-       0x07, /* V4L2_COLORFX_NEGATIVE */
-       0x04, /* V4L2_COLORFX_EMBOSS */
-       0x0f, /* V4L2_COLORFX_SKETCH */
-       0x08, /* V4L2_COLORFX_SKY_BLUE */
-       0x09, /* V4L2_COLORFX_GRASS_GREEN */
-       0x0a, /* V4L2_COLORFX_SKIN_WHITEN */
-       0x00, /* V4L2_COLORFX_VIVID */
-       0x00, /* V4L2_COLORFX_AQUA */
-       0x00, /* V4L2_COLORFX_ART_FREEZE */
-       0x00, /* V4L2_COLORFX_SILHOUETTE */
-       0x10, /* V4L2_COLORFX_SOLARIZATION */
-       0x02, /* V4L2_COLORFX_ANTIQUE */
-       0x00, /* V4L2_COLORFX_SET_CBCR */
-};
-
-static int ap1302_set_special_effect(struct v4l2_subdev *sd, s32 val)
-{
-       ap1302_i2c_write_reg(sd, REG_SFX_MODE, AP1302_REG16,
-               ap1302_sfx_values[val]);
-       return 0;
-}
-
-static u16 ap1302_scene_mode_values[] = {
-       0x00, /* V4L2_SCENE_MODE_NONE */
-       0x07, /* V4L2_SCENE_MODE_BACKLIGHT */
-       0x0a, /* V4L2_SCENE_MODE_BEACH_SNOW */
-       0x06, /* V4L2_SCENE_MODE_CANDLE_LIGHT */
-       0x00, /* V4L2_SCENE_MODE_DAWN_DUSK */
-       0x00, /* V4L2_SCENE_MODE_FALL_COLORS */
-       0x0d, /* V4L2_SCENE_MODE_FIREWORKS */
-       0x02, /* V4L2_SCENE_MODE_LANDSCAPE */
-       0x05, /* V4L2_SCENE_MODE_NIGHT */
-       0x0c, /* V4L2_SCENE_MODE_PARTY_INDOOR */
-       0x01, /* V4L2_SCENE_MODE_PORTRAIT */
-       0x03, /* V4L2_SCENE_MODE_SPORTS */
-       0x0e, /* V4L2_SCENE_MODE_SUNSET */
-       0x0b, /* V4L2_SCENE_MODE_TEXT */
-};
-
-static int ap1302_set_scene_mode(struct v4l2_subdev *sd, s32 val)
-{
-       ap1302_i2c_write_reg(sd, REG_SCENE_CTRL, AP1302_REG16,
-               ap1302_scene_mode_values[val]);
-       return 0;
-}
-
-static u16 ap1302_flicker_values[] = {
-       0x0,    /* OFF */
-       0x3201, /* 50HZ */
-       0x3c01, /* 60HZ */
-       0x2     /* AUTO */
-};
-
-static int ap1302_set_flicker_freq(struct v4l2_subdev *sd, s32 val)
-{
-       ap1302_i2c_write_reg(sd, REG_FLICK_CTRL, AP1302_REG16,
-               ap1302_flicker_values[val]);
-       return 0;
-}
-
-static int ap1302_s_ctrl(struct v4l2_ctrl *ctrl)
-{
-       struct ap1302_device *dev = container_of(
-               ctrl->handler, struct ap1302_device, ctrl_handler);
-
-       switch (ctrl->id) {
-       case V4L2_CID_RUN_MODE:
-               dev->cur_context = ap1302_cntx_mapping[ctrl->val];
-               break;
-       case V4L2_CID_EXPOSURE:
-               ap1302_set_exposure_off(&dev->sd, ctrl->val);
-               break;
-       case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
-               ap1302_set_wb_mode(&dev->sd, ctrl->val);
-               break;
-       case V4L2_CID_ZOOM_ABSOLUTE:
-               ap1302_set_zoom(&dev->sd, ctrl->val);
-               break;
-       case V4L2_CID_COLORFX:
-               ap1302_set_special_effect(&dev->sd, ctrl->val);
-               break;
-       case V4L2_CID_SCENE_MODE:
-               ap1302_set_scene_mode(&dev->sd, ctrl->val);
-               break;
-       case V4L2_CID_POWER_LINE_FREQUENCY:
-               ap1302_set_flicker_freq(&dev->sd, ctrl->val);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int ap1302_g_register(struct v4l2_subdev *sd,
-                            struct v4l2_dbg_register *reg)
-{
-       struct ap1302_device *dev = to_ap1302_device(sd);
-       int ret;
-       u32 reg_val;
-
-       if (reg->size != AP1302_REG16 &&
-           reg->size != AP1302_REG32)
-               return -EINVAL;
-
-       mutex_lock(&dev->input_lock);
-       if (dev->power_on)
-               ret = ap1302_i2c_read_reg(sd, reg->reg, reg->size, &reg_val);
-       else
-               ret = -EIO;
-       mutex_unlock(&dev->input_lock);
-       if (ret)
-               return ret;
-
-       reg->val = reg_val;
-
-       return 0;
-}
-
-static int ap1302_s_register(struct v4l2_subdev *sd,
-                            const struct v4l2_dbg_register *reg)
-{
-       struct ap1302_device *dev = to_ap1302_device(sd);
-       int ret;
-
-       if (reg->size != AP1302_REG16 &&
-           reg->size != AP1302_REG32)
-               return -EINVAL;
-
-       mutex_lock(&dev->input_lock);
-       if (dev->power_on)
-               ret = ap1302_i2c_write_reg(sd, reg->reg, reg->size, reg->val);
-       else
-               ret = -EIO;
-       mutex_unlock(&dev->input_lock);
-       return ret;
-}
-
-static long ap1302_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
-{
-       long ret = 0;
-       switch (cmd) {
-       case VIDIOC_DBG_G_REGISTER:
-               ret = ap1302_g_register(sd, arg);
-               break;
-       case VIDIOC_DBG_S_REGISTER:
-               ret = ap1302_s_register(sd, arg);
-               break;
-       default:
-               ret = -EINVAL;
-       }
-       return ret;
-}
-
-static const struct v4l2_ctrl_ops ctrl_ops = {
-       .s_ctrl = ap1302_s_ctrl,
-};
-
-static const char * const ctrl_run_mode_menu[] = {
-       NULL,
-       "Video",
-       "Still capture",
-       "Continuous capture",
-       "Preview",
-};
-
-static const struct v4l2_ctrl_config ctrls[] = {
-       {
-               .ops = &ctrl_ops,
-               .id = V4L2_CID_RUN_MODE,
-               .name = "Run Mode",
-               .type = V4L2_CTRL_TYPE_MENU,
-               .min = 1,
-               .def = 4,
-               .max = 4,
-               .qmenu = ctrl_run_mode_menu,
-       },
-       {
-               .ops = &ctrl_ops,
-               .id = V4L2_CID_EXPOSURE,
-               .name = "Exposure",
-               .type = V4L2_CTRL_TYPE_INTEGER,
-               .min = AP1302_MIN_EV,
-               .def = 0,
-               .max = AP1302_MAX_EV,
-               .step = 1,
-       },
-       {
-               .ops = &ctrl_ops,
-               .id = V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE,
-               .name = "White Balance",
-               .type = V4L2_CTRL_TYPE_INTEGER,
-               .min = 0,
-               .def = 0,
-               .max = 9,
-               .step = 1,
-       },
-       {
-               .ops = &ctrl_ops,
-               .id = V4L2_CID_ZOOM_ABSOLUTE,
-               .name = "Zoom Absolute",
-               .type = V4L2_CTRL_TYPE_INTEGER,
-               .min = 0,
-               .def = 0,
-               .max = 1024,
-               .step = 1,
-       },
-       {
-               .ops = &ctrl_ops,
-               .id = V4L2_CID_COLORFX,
-               .name = "Color Special Effect",
-               .type = V4L2_CTRL_TYPE_INTEGER,
-               .min = 0,
-               .def = 0,
-               .max = 15,
-               .step = 1,
-       },
-       {
-               .ops = &ctrl_ops,
-               .id = V4L2_CID_SCENE_MODE,
-               .name = "Scene Mode",
-               .type = V4L2_CTRL_TYPE_INTEGER,
-               .min = 0,
-               .def = 0,
-               .max = 13,
-               .step = 1,
-       },
-       {
-               .ops = &ctrl_ops,
-               .id = V4L2_CID_POWER_LINE_FREQUENCY,
-               .name = "Light frequency filter",
-               .type = V4L2_CTRL_TYPE_INTEGER,
-               .min = 0,
-               .def = 3,
-               .max = 3,
-               .step = 1,
-       },
-};
-
-static const struct v4l2_subdev_sensor_ops ap1302_sensor_ops = {
-       .g_skip_frames  = ap1302_g_skip_frames,
-};
-
-static const struct v4l2_subdev_video_ops ap1302_video_ops = {
-       .s_stream = ap1302_s_stream,
-       .g_frame_interval = ap1302_g_frame_interval,
-};
-
-static const struct v4l2_subdev_core_ops ap1302_core_ops = {
-       .s_power = ap1302_s_power,
-       .ioctl = ap1302_ioctl,
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-       .g_register = ap1302_g_register,
-       .s_register = ap1302_s_register,
-#endif
-};
-
-static const struct v4l2_subdev_pad_ops ap1302_pad_ops = {
-       .enum_mbus_code = ap1302_enum_mbus_code,
-       .enum_frame_size = ap1302_enum_frame_size,
-       .get_fmt = ap1302_get_fmt,
-       .set_fmt = ap1302_set_fmt,
-};
-
-static const struct v4l2_subdev_ops ap1302_ops = {
-       .core = &ap1302_core_ops,
-       .pad = &ap1302_pad_ops,
-       .video = &ap1302_video_ops,
-       .sensor = &ap1302_sensor_ops
-};
-
-static int ap1302_remove(struct i2c_client *client)
-{
-       struct v4l2_subdev *sd = i2c_get_clientdata(client);
-       struct ap1302_device *dev = to_ap1302_device(sd);
-
-       if (dev->platform_data->platform_deinit)
-               dev->platform_data->platform_deinit();
-
-       release_firmware(dev->fw);
-
-       media_entity_cleanup(&dev->sd.entity);
-       dev->platform_data->csi_cfg(sd, 0);
-       v4l2_device_unregister_subdev(sd);
-
-       return 0;
-}
-
-static int ap1302_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
-{
-       struct ap1302_device *dev;
-       int ret;
-       unsigned int i;
-
-       dev_info(&client->dev, "ap1302 probe called.\n");
-
-       /* allocate device & init sub device */
-       dev = devm_kzalloc(&client->dev, sizeof(*dev), GFP_KERNEL);
-       if (!dev) {
-               dev_err(&client->dev, "%s: out of memory\n", __func__);
-               return -ENOMEM;
-       }
-
-       mutex_init(&dev->input_lock);
-
-       v4l2_i2c_subdev_init(&(dev->sd), client, &ap1302_ops);
-
-       ret = ap1302_request_firmware(&(dev->sd));
-       if (ret) {
-               dev_err(&client->dev, "Cannot request ap1302 firmware.\n");
-               goto out_free;
-       }
-
-       dev->regmap16 = devm_regmap_init_i2c(client, &ap1302_reg16_config);
-       if (IS_ERR(dev->regmap16)) {
-               ret = PTR_ERR(dev->regmap16);
-               dev_err(&client->dev,
-                       "Failed to allocate 16bit register map: %d\n", ret);
-               return ret;
-       }
-
-       dev->regmap32 = devm_regmap_init_i2c(client, &ap1302_reg32_config);
-       if (IS_ERR(dev->regmap32)) {
-               ret = PTR_ERR(dev->regmap32);
-               dev_err(&client->dev,
-                       "Failed to allocate 32bit register map: %d\n", ret);
-               return ret;
-       }
-
-       if (client->dev.platform_data) {
-               ret = ap1302_s_config(&dev->sd, client->dev.platform_data);
-               if (ret)
-                       goto out_free;
-       }
-
-       dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-       dev->pad.flags = MEDIA_PAD_FL_SOURCE;
-       dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
-
-       dev->cntx_res[CONTEXT_PREVIEW].res_num = ARRAY_SIZE(ap1302_preview_res);
-       dev->cntx_res[CONTEXT_PREVIEW].res_table = ap1302_preview_res;
-       dev->cntx_res[CONTEXT_SNAPSHOT].res_num =
-               ARRAY_SIZE(ap1302_snapshot_res);
-       dev->cntx_res[CONTEXT_SNAPSHOT].res_table = ap1302_snapshot_res;
-       dev->cntx_res[CONTEXT_VIDEO].res_num = ARRAY_SIZE(ap1302_video_res);
-       dev->cntx_res[CONTEXT_VIDEO].res_table = ap1302_video_res;
-
-       ret = v4l2_ctrl_handler_init(&dev->ctrl_handler, ARRAY_SIZE(ctrls));
-       if (ret) {
-               ap1302_remove(client);
-               return ret;
-       }
-
-       for (i = 0; i < ARRAY_SIZE(ctrls); i++)
-               v4l2_ctrl_new_custom(&dev->ctrl_handler, &ctrls[i], NULL);
-
-       if (dev->ctrl_handler.error) {
-               ap1302_remove(client);
-               return dev->ctrl_handler.error;
-       }
-
-       /* Use same lock for controls as for everything else. */
-       dev->ctrl_handler.lock = &dev->input_lock;
-       dev->sd.ctrl_handler = &dev->ctrl_handler;
-       v4l2_ctrl_handler_setup(&dev->ctrl_handler);
-
-       dev->run_mode = v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_RUN_MODE);
-       v4l2_ctrl_s_ctrl(dev->run_mode, ATOMISP_RUN_MODE_PREVIEW);
-
-       ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad);
-       if (ret)
-               ap1302_remove(client);
-       return ret;
-out_free:
-       v4l2_device_unregister_subdev(&dev->sd);
-       return ret;
-}
-
-static const struct i2c_device_id ap1302_id[] = {
-       {AP1302_NAME, 0},
-       {}
-};
-MODULE_DEVICE_TABLE(i2c, ap1302_id);
-
-static struct i2c_driver ap1302_driver = {
-       .driver = {
-               .name = AP1302_NAME,
-       },
-       .probe = ap1302_probe,
-       .remove = ap1302_remove,
-       .id_table = ap1302_id,
-};
-
-module_i2c_driver(ap1302_driver);
-
-MODULE_AUTHOR("Tianshu Qiu <tian.shu.qiu@intel.com>");
-MODULE_DESCRIPTION("AP1302 Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ap1302.c b/drivers/staging/media/atomisp/i2c/atomisp-ap1302.c
new file mode 100644 (file)
index 0000000..2f772a0
--- /dev/null
@@ -0,0 +1,1255 @@
+/*
+ *
+ * Copyright (c) 2013 Intel Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "../include/linux/atomisp.h"
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include "ap1302.h"
+
+#define to_ap1302_device(sub_dev) \
+               container_of(sub_dev, struct ap1302_device, sd)
+
+/* Static definitions */
+static struct regmap_config ap1302_reg16_config = {
+       .reg_bits = 16,
+       .val_bits = 16,
+       .reg_format_endian = REGMAP_ENDIAN_BIG,
+       .val_format_endian = REGMAP_ENDIAN_BIG,
+};
+
+static struct regmap_config ap1302_reg32_config = {
+       .reg_bits = 16,
+       .val_bits = 32,
+       .reg_format_endian = REGMAP_ENDIAN_BIG,
+       .val_format_endian = REGMAP_ENDIAN_BIG,
+};
+
+static enum ap1302_contexts ap1302_cntx_mapping[] = {
+       CONTEXT_PREVIEW,        /* Invalid atomisp run mode */
+       CONTEXT_VIDEO,          /* ATOMISP_RUN_MODE_VIDEO */
+       CONTEXT_SNAPSHOT,       /* ATOMISP_RUN_MODE_STILL_CAPTURE */
+       CONTEXT_SNAPSHOT,       /* ATOMISP_RUN_MODE_CONTINUOUS_CAPTURE */
+       CONTEXT_PREVIEW,        /* ATOMISP_RUN_MODE_PREVIEW */
+};
+
+static struct ap1302_res_struct ap1302_preview_res[] = {
+       {
+               .width = 640,
+               .height = 480,
+               .fps = 30,
+       },
+       {
+               .width = 720,
+               .height = 480,
+               .fps = 30,
+       },
+       {
+               .width = 1280,
+               .height = 720,
+               .fps = 30,
+       },
+       {
+               .width = 1920,
+               .height = 1080,
+               .fps = 30,
+       }
+};
+
+static struct ap1302_res_struct ap1302_snapshot_res[] = {
+       {
+               .width = 640,
+               .height = 480,
+               .fps = 30,
+       },
+       {
+               .width = 720,
+               .height = 480,
+               .fps = 30,
+       },
+       {
+               .width = 1280,
+               .height = 720,
+               .fps = 30,
+       },
+       {
+               .width = 1920,
+               .height = 1080,
+               .fps = 30,
+       }
+};
+
+static struct ap1302_res_struct ap1302_video_res[] = {
+       {
+               .width = 640,
+               .height = 480,
+               .fps = 30,
+       },
+       {
+               .width = 720,
+               .height = 480,
+               .fps = 30,
+       },
+       {
+               .width = 1280,
+               .height = 720,
+               .fps = 30,
+       },
+       {
+               .width = 1920,
+               .height = 1080,
+               .fps = 30,
+       }
+};
+
+static enum ap1302_contexts stream_to_context[] = {
+       CONTEXT_SNAPSHOT,
+       CONTEXT_PREVIEW,
+       CONTEXT_PREVIEW,
+       CONTEXT_VIDEO
+};
+
+static u16 aux_stream_config[CONTEXT_NUM][CONTEXT_NUM] = {
+       {0, 0, 0},      /* Preview: No aux streams. */
+       {1, 0, 2},      /* Snapshot: 1 for postview. 2 for video */
+       {1, 0, 0},      /* Video: 1 for preview. */
+};
+
+static struct ap1302_context_info context_info[] = {
+       {CNTX_WIDTH, AP1302_REG16, "width"},
+       {CNTX_HEIGHT, AP1302_REG16, "height"},
+       {CNTX_ROI_X0, AP1302_REG16, "roi_x0"},
+       {CNTX_ROI_X1, AP1302_REG16, "roi_x1"},
+       {CNTX_ROI_Y0, AP1302_REG16, "roi_y0"},
+       {CNTX_ROI_Y1, AP1302_REG16, "roi_y1"},
+       {CNTX_ASPECT, AP1302_REG16, "aspect"},
+       {CNTX_LOCK, AP1302_REG16, "lock"},
+       {CNTX_ENABLE, AP1302_REG16, "enable"},
+       {CNTX_OUT_FMT, AP1302_REG16, "out_fmt"},
+       {CNTX_SENSOR_MODE, AP1302_REG16, "sensor_mode"},
+       {CNTX_MIPI_CTRL, AP1302_REG16, "mipi_ctrl"},
+       {CNTX_MIPI_II_CTRL, AP1302_REG16, "mipi_ii_ctrl"},
+       {CNTX_LINE_TIME, AP1302_REG32, "line_time"},
+       {CNTX_MAX_FPS, AP1302_REG16, "max_fps"},
+       {CNTX_AE_USG, AP1302_REG16, "ae_usg"},
+       {CNTX_AE_UPPER_ET, AP1302_REG32, "ae_upper_et"},
+       {CNTX_AE_MAX_ET, AP1302_REG32, "ae_max_et"},
+       {CNTX_SS, AP1302_REG16, "ss"},
+       {CNTX_S1_SENSOR_MODE, AP1302_REG16, "s1_sensor_mode"},
+       {CNTX_HINF_CTRL, AP1302_REG16, "hinf_ctrl"},
+};
+
+/* This array stores the description list for metadata.
+   The metadata contains exposure settings and face
+   detection results. */
+static u16 ap1302_ss_list[] = {
+       0xb01c, /* From 0x0186 with size 0x1C are exposure settings. */
+       0x0186,
+       0xb002, /* 0x71c0 is for F-number */
+       0x71c0,
+       0xb010, /* From 0x03dc with size 0x10 are face general infos. */
+       0x03dc,
+       0xb0a0, /* From 0x03e4 with size 0xa0 are face detail infos. */
+       0x03e4,
+       0xb020, /* From 0x0604 with size 0x20 are smile rate infos. */
+       0x0604,
+       0x0000
+};
+
+/* End of static definitions */
+
+static int ap1302_i2c_read_reg(struct v4l2_subdev *sd,
+                               u16 reg, u16 len, void *val)
+{
+       struct ap1302_device *dev = to_ap1302_device(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret;
+
+       if (len == AP1302_REG16)
+               ret = regmap_read(dev->regmap16, reg, val);
+       else if (len == AP1302_REG32)
+               ret = regmap_read(dev->regmap32, reg, val);
+       else
+               ret = -EINVAL;
+       if (ret) {
+               dev_dbg(&client->dev, "Read reg failed. reg=0x%04X\n", reg);
+               return ret;
+       }
+       if (len == AP1302_REG16)
+               dev_dbg(&client->dev, "read_reg[0x%04X] = 0x%04X\n",
+                       reg, *(u16 *)val);
+       else
+               dev_dbg(&client->dev, "read_reg[0x%04X] = 0x%08X\n",
+                       reg, *(u32 *)val);
+       return ret;
+}
+
+static int ap1302_i2c_write_reg(struct v4l2_subdev *sd,
+                               u16 reg, u16 len, u32 val)
+{
+       struct ap1302_device *dev = to_ap1302_device(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret;
+       if (len == AP1302_REG16)
+               ret = regmap_write(dev->regmap16, reg, val);
+       else if (len == AP1302_REG32)
+               ret = regmap_write(dev->regmap32, reg, val);
+       else
+               ret = -EINVAL;
+       if (ret) {
+               dev_dbg(&client->dev, "Write reg failed. reg=0x%04X\n", reg);
+               return ret;
+       }
+       if (len == AP1302_REG16)
+               dev_dbg(&client->dev, "write_reg[0x%04X] = 0x%04X\n",
+                       reg, (u16)val);
+       else
+               dev_dbg(&client->dev, "write_reg[0x%04X] = 0x%08X\n",
+                       reg, (u32)val);
+       return ret;
+}
+
+static u16
+ap1302_calculate_context_reg_addr(enum ap1302_contexts context, u16 offset)
+{
+       u16 reg_addr;
+       /* The register offset is defined according to preview/video registers.
+          Preview and video context have the same register definition.
+          But snapshot context does not have register S1_SENSOR_MODE.
+          When setting snapshot registers, if the offset exceeds
+          S1_SENSOR_MODE, the actual offset needs to minus 2. */
+       if (context == CONTEXT_SNAPSHOT) {
+               if (offset == CNTX_S1_SENSOR_MODE)
+                       return 0;
+               if (offset > CNTX_S1_SENSOR_MODE)
+                       offset -= 2;
+       }
+       if (context == CONTEXT_PREVIEW)
+               reg_addr = REG_PREVIEW_BASE + offset;
+       else if (context == CONTEXT_VIDEO)
+               reg_addr = REG_VIDEO_BASE + offset;
+       else
+               reg_addr = REG_SNAPSHOT_BASE + offset;
+       return reg_addr;
+}
+
+static int ap1302_read_context_reg(struct v4l2_subdev *sd,
+               enum ap1302_contexts context, u16 offset, u16 len)
+{
+       struct ap1302_device *dev = to_ap1302_device(sd);
+       u16 reg_addr = ap1302_calculate_context_reg_addr(context, offset);
+       if (reg_addr == 0)
+               return -EINVAL;
+       return ap1302_i2c_read_reg(sd, reg_addr, len,
+                           ((u8 *)&dev->cntx_config[context]) + offset);
+}
+
+static int ap1302_write_context_reg(struct v4l2_subdev *sd,
+               enum ap1302_contexts context, u16 offset, u16 len)
+{
+       struct ap1302_device *dev = to_ap1302_device(sd);
+       u16 reg_addr = ap1302_calculate_context_reg_addr(context, offset);
+       if (reg_addr == 0)
+               return -EINVAL;
+       return ap1302_i2c_write_reg(sd, reg_addr, len,
+                       *(u32 *)(((u8 *)&dev->cntx_config[context]) + offset));
+}
+
+static int ap1302_dump_context_reg(struct v4l2_subdev *sd,
+                                  enum ap1302_contexts context)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct ap1302_device *dev = to_ap1302_device(sd);
+       int i;
+       dev_dbg(&client->dev, "Dump registers for context[%d]:\n", context);
+       for (i = 0; i < ARRAY_SIZE(context_info); i++) {
+               struct ap1302_context_info *info = &context_info[i];
+               u8 *var = (u8 *)&dev->cntx_config[context] + info->offset;
+               /* Snapshot context does not have s1_sensor_mode register. */
+               if (context == CONTEXT_SNAPSHOT &&
+                       info->offset == CNTX_S1_SENSOR_MODE)
+                       continue;
+               ap1302_read_context_reg(sd, context, info->offset, info->len);
+               if (info->len == AP1302_REG16)
+                       dev_dbg(&client->dev, "context.%s = 0x%04X (%d)\n",
+                               info->name, *(u16 *)var, *(u16 *)var);
+               else
+                       dev_dbg(&client->dev, "context.%s = 0x%08X (%d)\n",
+                               info->name, *(u32 *)var, *(u32 *)var);
+       }
+       return 0;
+}
+
+static int ap1302_request_firmware(struct v4l2_subdev *sd)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct ap1302_device *dev = to_ap1302_device(sd);
+       int ret;
+       ret = request_firmware(&dev->fw, "ap1302_fw.bin", &client->dev);
+       if (ret)
+               dev_err(&client->dev,
+                       "ap1302_request_firmware failed. ret=%d\n", ret);
+       return ret;
+}
+
+/* When loading firmware, host writes firmware data from address 0x8000.
+   When the address reaches 0x9FFF, the next address should return to 0x8000.
+   This function handles this address window and load firmware data to AP1302.
+   win_pos indicates the offset within this window. Firmware loading procedure
+   may call this function several times. win_pos records the current position
+   that has been written to.*/
+static int ap1302_write_fw_window(struct v4l2_subdev *sd,
+                                 u16 *win_pos, const u8 *buf, u32 len)
+{
+       struct ap1302_device *dev = to_ap1302_device(sd);
+       int ret;
+       u32 pos;
+       u32 sub_len;
+       for (pos = 0; pos < len; pos += sub_len) {
+               if (len - pos < AP1302_FW_WINDOW_SIZE - *win_pos)
+                       sub_len = len - pos;
+               else
+                       sub_len = AP1302_FW_WINDOW_SIZE - *win_pos;
+               ret = regmap_raw_write(dev->regmap16,
+                                       *win_pos + AP1302_FW_WINDOW_OFFSET,
+                                       buf + pos, sub_len);
+               if (ret)
+                       return ret;
+               *win_pos += sub_len;
+               if (*win_pos >= AP1302_FW_WINDOW_SIZE)
+                       *win_pos = 0;
+       }
+       return 0;
+}
+
+static int ap1302_load_firmware(struct v4l2_subdev *sd)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct ap1302_device *dev = to_ap1302_device(sd);
+       const struct ap1302_firmware *fw;
+       const u8 *fw_data;
+       u16 reg_val = 0;
+       u16 win_pos = 0;
+       int ret;
+
+       dev_info(&client->dev, "Start to load firmware.\n");
+       if (!dev->fw) {
+               dev_err(&client->dev, "firmware not requested.\n");
+               return -EINVAL;
+       }
+       fw = (const struct ap1302_firmware *) dev->fw->data;
+       if (dev->fw->size != (sizeof(*fw) + fw->total_size)) {
+               dev_err(&client->dev, "firmware size does not match.\n");
+               return -EINVAL;
+       }
+       /* The fw binary contains a header of struct ap1302_firmware.
+          Following the header is the bootdata of AP1302.
+          The bootdata pointer can be referenced as &fw[1]. */
+       fw_data = (u8 *)&fw[1];
+
+       /* Clear crc register. */
+       ret = ap1302_i2c_write_reg(sd, REG_SIP_CRC, AP1302_REG16, 0xFFFF);
+       if (ret)
+               return ret;
+
+       /* Load FW data for PLL init stage. */
+       ret = ap1302_write_fw_window(sd, &win_pos, fw_data, fw->pll_init_size);
+       if (ret)
+               return ret;
+
+       /* Write 2 to bootdata_stage register to apply basic_init_hp
+          settings and enable PLL. */
+       ret = ap1302_i2c_write_reg(sd, REG_BOOTDATA_STAGE,
+                                  AP1302_REG16, 0x0002);
+       if (ret)
+               return ret;
+
+       /* Wait 1ms for PLL to lock. */
+       msleep(20);
+
+       /* Load the rest of bootdata content. */
+       ret = ap1302_write_fw_window(sd, &win_pos, fw_data + fw->pll_init_size,
+                                    fw->total_size - fw->pll_init_size);
+       if (ret)
+               return ret;
+
+       /* Check crc. */
+       ret = ap1302_i2c_read_reg(sd, REG_SIP_CRC, AP1302_REG16, &reg_val);
+       if (ret)
+               return ret;
+       if (reg_val != fw->crc) {
+               dev_err(&client->dev,
+                       "crc does not match. T:0x%04X F:0x%04X\n",
+                       fw->crc, reg_val);
+               return -EAGAIN;
+       }
+
+       /* Write 0xFFFF to bootdata_stage register to indicate AP1302 that
+          the whole bootdata content has been loaded. */
+       ret = ap1302_i2c_write_reg(sd, REG_BOOTDATA_STAGE,
+                                  AP1302_REG16, 0xFFFF);
+       if (ret)
+               return ret;
+       dev_info(&client->dev, "Load firmware successfully.\n");
+
+       return 0;
+}
+
+static int __ap1302_s_power(struct v4l2_subdev *sd, int on, int load_fw)
+{
+       struct ap1302_device *dev = to_ap1302_device(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret, i;
+       u16 ss_ptr;
+
+       dev_info(&client->dev, "ap1302_s_power is called.\n");
+       ret = dev->platform_data->power_ctrl(sd, on);
+       if (ret) {
+               dev_err(&client->dev,
+                       "ap1302_s_power error. on=%d ret=%d\n", on, ret);
+               return ret;
+       }
+       dev->power_on = on;
+       if (!on || !load_fw)
+               return 0;
+       /* Load firmware after power on. */
+       ret = ap1302_load_firmware(sd);
+       if (ret) {
+               dev_err(&client->dev,
+                       "ap1302_load_firmware failed. ret=%d\n", ret);
+               return ret;
+       }
+       ret = ap1302_i2c_read_reg(sd, REG_SS_HEAD_PT0, AP1302_REG16, &ss_ptr);
+       if (ret)
+               return ret;
+       for (i = 0; i < ARRAY_SIZE(ap1302_ss_list); i++) {
+               ret = ap1302_i2c_write_reg(sd, ss_ptr + i * 2,
+                       AP1302_REG16, ap1302_ss_list[i]);
+               if (ret)
+                       return ret;
+       }
+       return ret;
+}
+
+static int ap1302_s_power(struct v4l2_subdev *sd, int on)
+{
+       struct ap1302_device *dev = to_ap1302_device(sd);
+       int ret;
+
+       mutex_lock(&dev->input_lock);
+       ret = __ap1302_s_power(sd, on, 1);
+       dev->sys_activated = 0;
+       mutex_unlock(&dev->input_lock);
+
+       return ret;
+}
+
+static int ap1302_s_config(struct v4l2_subdev *sd, void *pdata)
+{
+       struct ap1302_device *dev = to_ap1302_device(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct camera_mipi_info *mipi_info;
+       u16 reg_val = 0;
+       int ret;
+
+       dev_info(&client->dev, "ap1302_s_config is called.\n");
+       if (pdata == NULL)
+               return -ENODEV;
+
+       dev->platform_data = pdata;
+
+       mutex_lock(&dev->input_lock);
+
+       if (dev->platform_data->platform_init) {
+               ret = dev->platform_data->platform_init(client);
+               if (ret)
+                       goto fail_power;
+       }
+
+       ret = __ap1302_s_power(sd, 1, 0);
+       if (ret)
+               goto fail_power;
+
+       /* Detect for AP1302 */
+       ret = ap1302_i2c_read_reg(sd, REG_CHIP_VERSION, AP1302_REG16, &reg_val);
+       if (ret || (reg_val != AP1302_CHIP_ID)) {
+               dev_err(&client->dev,
+                       "Chip version does no match. ret=%d ver=0x%04x\n",
+                       ret, reg_val);
+               goto fail_config;
+       }
+       dev_info(&client->dev, "AP1302 Chip ID is 0x%X\n", reg_val);
+
+       /* Detect revision for AP1302 */
+       ret = ap1302_i2c_read_reg(sd, REG_CHIP_REV, AP1302_REG16, &reg_val);
+       if (ret)
+               goto fail_config;
+       dev_info(&client->dev, "AP1302 Chip Rev is 0x%X\n", reg_val);
+       ret = dev->platform_data->csi_cfg(sd, 1);
+       if (ret)
+               goto fail_config;
+
+       mipi_info = v4l2_get_subdev_hostdata(sd);
+       if (!mipi_info)
+               goto fail_config;
+       dev->num_lanes = mipi_info->num_lanes;
+
+       ret = __ap1302_s_power(sd, 0, 0);
+       if (ret)
+               goto fail_power;
+
+       mutex_unlock(&dev->input_lock);
+
+       return ret;
+
+fail_config:
+       __ap1302_s_power(sd, 0, 0);
+fail_power:
+       mutex_unlock(&dev->input_lock);
+       dev_err(&client->dev, "ap1302_s_config failed\n");
+       return ret;
+}
+
+static enum ap1302_contexts ap1302_get_context(struct v4l2_subdev *sd)
+{
+       struct ap1302_device *dev = to_ap1302_device(sd);
+       return dev->cur_context;
+}
+
+static int ap1302_enum_mbus_code(struct v4l2_subdev *sd,
+                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_mbus_code_enum *code)
+{
+       if (code->index)
+               return -EINVAL;
+
+       code->code = MEDIA_BUS_FMT_UYVY8_1X16;
+
+       return 0;
+}
+
+static int ap1302_match_resolution(struct ap1302_context_res *res,
+                                  struct v4l2_mbus_framefmt *fmt)
+{
+       s32 w0, h0, mismatch, distance;
+       s32 w1 = fmt->width;
+       s32 h1 = fmt->height;
+       s32 min_distance = INT_MAX;
+       s32 i, idx = -1;
+
+       if (w1 == 0 || h1 == 0)
+               return -1;
+
+       for (i = 0; i < res->res_num; i++) {
+               w0 = res->res_table[i].width;
+               h0 = res->res_table[i].height;
+               if (w0 < w1 || h0 < h1)
+                       continue;
+               mismatch = abs(w0 * h1 - w1 * h0) * 8192 / w1 / h0;
+               if (mismatch > 8192 * AP1302_MAX_RATIO_MISMATCH / 100)
+                       continue;
+               distance = (w0 * h1 + w1 * h0) * 8192 / w1 / h1;
+               if (distance < min_distance) {
+                       min_distance = distance;
+                       idx = i;
+               }
+       }
+
+       return idx;
+}
+
+static s32 ap1302_try_mbus_fmt_locked(struct v4l2_subdev *sd,
+                               enum ap1302_contexts context,
+                               struct v4l2_mbus_framefmt *fmt)
+{
+       struct ap1302_device *dev = to_ap1302_device(sd);
+       struct ap1302_res_struct *res_table;
+       s32 res_num, idx = -1;
+
+       res_table = dev->cntx_res[context].res_table;
+       res_num = dev->cntx_res[context].res_num;
+
+       if ((fmt->width <= res_table[res_num - 1].width) &&
+               (fmt->height <= res_table[res_num - 1].height))
+               idx = ap1302_match_resolution(&dev->cntx_res[context], fmt);
+       if (idx == -1)
+               idx = res_num - 1;
+
+       fmt->width = res_table[idx].width;
+       fmt->height = res_table[idx].height;
+       fmt->code = MEDIA_BUS_FMT_UYVY8_1X16;
+       return idx;
+}
+
+
+static int ap1302_get_fmt(struct v4l2_subdev *sd,
+                        struct v4l2_subdev_pad_config *cfg,
+                                        struct v4l2_subdev_format *format)
+
+{
+    struct v4l2_mbus_framefmt *fmt = &format->format;
+    struct ap1302_device *dev = to_ap1302_device(sd);
+       enum ap1302_contexts context;
+       struct ap1302_res_struct *res_table;
+       s32 cur_res;
+     if (format->pad)
+               return -EINVAL;
+       mutex_lock(&dev->input_lock);
+       context = ap1302_get_context(sd);
+       res_table = dev->cntx_res[context].res_table;
+       cur_res = dev->cntx_res[context].cur_res;
+       fmt->code = MEDIA_BUS_FMT_UYVY8_1X16;
+       fmt->width = res_table[cur_res].width;
+       fmt->height = res_table[cur_res].height;
+       mutex_unlock(&dev->input_lock);
+       return 0;
+}
+
+static int ap1302_set_fmt(struct v4l2_subdev *sd,
+                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_format *format)
+{
+       struct v4l2_mbus_framefmt *fmt = &format->format;
+       struct ap1302_device *dev = to_ap1302_device(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct atomisp_input_stream_info *stream_info =
+               (struct atomisp_input_stream_info *)fmt->reserved;
+       enum ap1302_contexts context, main_context;
+       if (format->pad)
+               return -EINVAL;
+       if (!fmt)
+               return -EINVAL;
+       mutex_lock(&dev->input_lock);
+       if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+               context = ap1302_get_context(sd);
+               ap1302_try_mbus_fmt_locked(sd, context, fmt);
+               cfg->try_fmt = *fmt;
+           mutex_unlock(&dev->input_lock);
+               return 0;
+               }
+       context = stream_to_context[stream_info->stream];
+       dev_dbg(&client->dev, "ap1302_set_mbus_fmt. stream=%d context=%d\n",
+               stream_info->stream, context);
+       dev->cntx_res[context].cur_res =
+               ap1302_try_mbus_fmt_locked(sd, context, fmt);
+       dev->cntx_config[context].width = fmt->width;
+       dev->cntx_config[context].height = fmt->height;
+       ap1302_write_context_reg(sd, context, CNTX_WIDTH, AP1302_REG16);
+       ap1302_write_context_reg(sd, context, CNTX_HEIGHT, AP1302_REG16);
+       ap1302_read_context_reg(sd, context, CNTX_OUT_FMT, AP1302_REG16);
+       dev->cntx_config[context].out_fmt &= ~OUT_FMT_TYPE_MASK;
+       dev->cntx_config[context].out_fmt |= AP1302_FMT_UYVY422;
+       ap1302_write_context_reg(sd, context, CNTX_OUT_FMT, AP1302_REG16);
+
+       main_context = ap1302_get_context(sd);
+       if (context == main_context) {
+               ap1302_read_context_reg(sd, context,
+                       CNTX_MIPI_CTRL, AP1302_REG16);
+               dev->cntx_config[context].mipi_ctrl &= ~MIPI_CTRL_IMGVC_MASK;
+               dev->cntx_config[context].mipi_ctrl |=
+                       (context << MIPI_CTRL_IMGVC_OFFSET);
+               dev->cntx_config[context].mipi_ctrl &= ~MIPI_CTRL_SSVC_MASK;
+               dev->cntx_config[context].mipi_ctrl |=
+                       (context << MIPI_CTRL_SSVC_OFFSET);
+               dev->cntx_config[context].mipi_ctrl &= ~MIPI_CTRL_SSTYPE_MASK;
+               dev->cntx_config[context].mipi_ctrl |=
+                       (0x12 << MIPI_CTRL_SSTYPE_OFFSET);
+               ap1302_write_context_reg(sd, context,
+                       CNTX_MIPI_CTRL, AP1302_REG16);
+               ap1302_read_context_reg(sd, context,
+                       CNTX_SS, AP1302_REG16);
+               dev->cntx_config[context].ss = AP1302_SS_CTRL;
+               ap1302_write_context_reg(sd, context,
+                       CNTX_SS, AP1302_REG16);
+       } else {
+               /* Configure aux stream */
+               ap1302_read_context_reg(sd, context,
+                       CNTX_MIPI_II_CTRL, AP1302_REG16);
+               dev->cntx_config[context].mipi_ii_ctrl &= ~MIPI_CTRL_IMGVC_MASK;
+               dev->cntx_config[context].mipi_ii_ctrl |=
+                       (context << MIPI_CTRL_IMGVC_OFFSET);
+               ap1302_write_context_reg(sd, context,
+                       CNTX_MIPI_II_CTRL, AP1302_REG16);
+               if (stream_info->enable) {
+                       ap1302_read_context_reg(sd, main_context,
+                               CNTX_OUT_FMT, AP1302_REG16);
+                       dev->cntx_config[context].out_fmt |=
+                               (aux_stream_config[main_context][context]
+                                << OUT_FMT_IIS_OFFSET);
+                       ap1302_write_context_reg(sd, main_context,
+                               CNTX_OUT_FMT, AP1302_REG16);
+               }
+       }
+       stream_info->ch_id = context;
+       mutex_unlock(&dev->input_lock);
+
+       return 0;
+}
+
+
+static int ap1302_g_frame_interval(struct v4l2_subdev *sd,
+                       struct v4l2_subdev_frame_interval *interval)
+{
+       struct ap1302_device *dev = to_ap1302_device(sd);
+       enum ap1302_contexts context;
+       struct ap1302_res_struct *res_table;
+       u32 cur_res;
+
+       mutex_lock(&dev->input_lock);
+       context = ap1302_get_context(sd);
+       res_table = dev->cntx_res[context].res_table;
+       cur_res = dev->cntx_res[context].cur_res;
+       interval->interval.denominator = res_table[cur_res].fps;
+       interval->interval.numerator = 1;
+       mutex_unlock(&dev->input_lock);
+       return 0;
+}
+
+static int ap1302_enum_frame_size(struct v4l2_subdev *sd,
+                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_frame_size_enum *fse)
+{
+       struct ap1302_device *dev = to_ap1302_device(sd);
+       enum ap1302_contexts context;
+       struct ap1302_res_struct *res_table;
+       int index = fse->index;
+
+       mutex_lock(&dev->input_lock);
+       context = ap1302_get_context(sd);
+       if (index >= dev->cntx_res[context].res_num) {
+               mutex_unlock(&dev->input_lock);
+               return -EINVAL;
+       }
+
+       res_table = dev->cntx_res[context].res_table;
+       fse->min_width = res_table[index].width;
+       fse->min_height = res_table[index].height;
+       fse->max_width = res_table[index].width;
+       fse->max_height = res_table[index].height;
+       mutex_unlock(&dev->input_lock);
+
+       return 0;
+}
+
+
+static int ap1302_g_skip_frames(struct v4l2_subdev *sd, u32 *frames)
+{
+       *frames = 0;
+       return 0;
+}
+
+static int ap1302_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct ap1302_device *dev = to_ap1302_device(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       enum ap1302_contexts context;
+       u32 reg_val;
+       int ret;
+
+       mutex_lock(&dev->input_lock);
+       context = ap1302_get_context(sd);
+       dev_dbg(&client->dev, "ap1302_s_stream. context=%d enable=%d\n",
+                       context, enable);
+       /* Switch context */
+       ap1302_i2c_read_reg(sd, REG_CTRL,
+                           AP1302_REG16, &reg_val);
+       reg_val &= ~CTRL_CNTX_MASK;
+       reg_val |= (context<<CTRL_CNTX_OFFSET);
+       ap1302_i2c_write_reg(sd, REG_CTRL,
+                           AP1302_REG16, reg_val);
+       /* Select sensor */
+       ap1302_i2c_read_reg(sd, REG_SENSOR_SELECT,
+                           AP1302_REG16, &reg_val);
+       reg_val &= ~SENSOR_SELECT_MASK;
+       reg_val |= (AP1302_SENSOR_PRI<<SENSOR_SELECT_OFFSET);
+       ap1302_i2c_write_reg(sd, REG_SENSOR_SELECT,
+                           AP1302_REG16, reg_val);
+       if (enable) {
+               dev_info(&client->dev, "Start stream. context=%d\n", context);
+               ap1302_dump_context_reg(sd, context);
+               if (!dev->sys_activated) {
+                       reg_val = AP1302_SYS_ACTIVATE;
+                       dev->sys_activated = 1;
+               } else {
+                       reg_val = AP1302_SYS_SWITCH;
+               }
+       } else {
+               dev_info(&client->dev, "Stop stream. context=%d\n", context);
+               reg_val = AP1302_SYS_SWITCH;
+       }
+       ret = ap1302_i2c_write_reg(sd, REG_SYS_START, AP1302_REG16, reg_val);
+       if (ret)
+               dev_err(&client->dev,
+                       "AP1302 set stream failed. enable=%d\n", enable);
+       mutex_unlock(&dev->input_lock);
+       return ret;
+}
+
+static u16 ap1302_ev_values[] = {0xfd00, 0xfe80, 0x0, 0x180, 0x300};
+
+static int ap1302_set_exposure_off(struct v4l2_subdev *sd, s32 val)
+{
+       val -= AP1302_MIN_EV;
+       return ap1302_i2c_write_reg(sd, REG_AE_BV_OFF, AP1302_REG16,
+                               ap1302_ev_values[val]);
+}
+
+static u16 ap1302_wb_values[] = {
+       0, /* V4L2_WHITE_BALANCE_MANUAL */
+       0xf, /* V4L2_WHITE_BALANCE_AUTO */
+       0x2, /* V4L2_WHITE_BALANCE_INCANDESCENT */
+       0x4, /* V4L2_WHITE_BALANCE_FLUORESCENT */
+       0x5, /* V4L2_WHITE_BALANCE_FLUORESCENT_H */
+       0x1, /* V4L2_WHITE_BALANCE_HORIZON */
+       0x5, /* V4L2_WHITE_BALANCE_DAYLIGHT */
+       0xf, /* V4L2_WHITE_BALANCE_FLASH */
+       0x6, /* V4L2_WHITE_BALANCE_CLOUDY */
+       0x6, /* V4L2_WHITE_BALANCE_SHADE */
+};
+
+static int ap1302_set_wb_mode(struct v4l2_subdev *sd, s32 val)
+{
+       int ret = 0;
+       u16 reg_val;
+
+       ret = ap1302_i2c_read_reg(sd, REG_AWB_CTRL, AP1302_REG16, &reg_val);
+       if (ret)
+               return ret;
+       reg_val &= ~AWB_CTRL_MODE_MASK;
+       reg_val |= ap1302_wb_values[val] << AWB_CTRL_MODE_OFFSET;
+       if (val == V4L2_WHITE_BALANCE_FLASH)
+               reg_val |= AWB_CTRL_FLASH_MASK;
+       else
+               reg_val &= ~AWB_CTRL_FLASH_MASK;
+       ret = ap1302_i2c_write_reg(sd, REG_AWB_CTRL, AP1302_REG16, reg_val);
+       return ret;
+}
+
+static int ap1302_set_zoom(struct v4l2_subdev *sd, s32 val)
+{
+       ap1302_i2c_write_reg(sd, REG_DZ_TGT_FCT, AP1302_REG16,
+               val * 4 + 0x100);
+       return 0;
+}
+
+static u16 ap1302_sfx_values[] = {
+       0x00, /* V4L2_COLORFX_NONE */
+       0x03, /* V4L2_COLORFX_BW */
+       0x0d, /* V4L2_COLORFX_SEPIA */
+       0x07, /* V4L2_COLORFX_NEGATIVE */
+       0x04, /* V4L2_COLORFX_EMBOSS */
+       0x0f, /* V4L2_COLORFX_SKETCH */
+       0x08, /* V4L2_COLORFX_SKY_BLUE */
+       0x09, /* V4L2_COLORFX_GRASS_GREEN */
+       0x0a, /* V4L2_COLORFX_SKIN_WHITEN */
+       0x00, /* V4L2_COLORFX_VIVID */
+       0x00, /* V4L2_COLORFX_AQUA */
+       0x00, /* V4L2_COLORFX_ART_FREEZE */
+       0x00, /* V4L2_COLORFX_SILHOUETTE */
+       0x10, /* V4L2_COLORFX_SOLARIZATION */
+       0x02, /* V4L2_COLORFX_ANTIQUE */
+       0x00, /* V4L2_COLORFX_SET_CBCR */
+};
+
+static int ap1302_set_special_effect(struct v4l2_subdev *sd, s32 val)
+{
+       ap1302_i2c_write_reg(sd, REG_SFX_MODE, AP1302_REG16,
+               ap1302_sfx_values[val]);
+       return 0;
+}
+
+static u16 ap1302_scene_mode_values[] = {
+       0x00, /* V4L2_SCENE_MODE_NONE */
+       0x07, /* V4L2_SCENE_MODE_BACKLIGHT */
+       0x0a, /* V4L2_SCENE_MODE_BEACH_SNOW */
+       0x06, /* V4L2_SCENE_MODE_CANDLE_LIGHT */
+       0x00, /* V4L2_SCENE_MODE_DAWN_DUSK */
+       0x00, /* V4L2_SCENE_MODE_FALL_COLORS */
+       0x0d, /* V4L2_SCENE_MODE_FIREWORKS */
+       0x02, /* V4L2_SCENE_MODE_LANDSCAPE */
+       0x05, /* V4L2_SCENE_MODE_NIGHT */
+       0x0c, /* V4L2_SCENE_MODE_PARTY_INDOOR */
+       0x01, /* V4L2_SCENE_MODE_PORTRAIT */
+       0x03, /* V4L2_SCENE_MODE_SPORTS */
+       0x0e, /* V4L2_SCENE_MODE_SUNSET */
+       0x0b, /* V4L2_SCENE_MODE_TEXT */
+};
+
+static int ap1302_set_scene_mode(struct v4l2_subdev *sd, s32 val)
+{
+       ap1302_i2c_write_reg(sd, REG_SCENE_CTRL, AP1302_REG16,
+               ap1302_scene_mode_values[val]);
+       return 0;
+}
+
+static u16 ap1302_flicker_values[] = {
+       0x0,    /* OFF */
+       0x3201, /* 50HZ */
+       0x3c01, /* 60HZ */
+       0x2     /* AUTO */
+};
+
+static int ap1302_set_flicker_freq(struct v4l2_subdev *sd, s32 val)
+{
+       ap1302_i2c_write_reg(sd, REG_FLICK_CTRL, AP1302_REG16,
+               ap1302_flicker_values[val]);
+       return 0;
+}
+
+static int ap1302_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct ap1302_device *dev = container_of(
+               ctrl->handler, struct ap1302_device, ctrl_handler);
+
+       switch (ctrl->id) {
+       case V4L2_CID_RUN_MODE:
+               dev->cur_context = ap1302_cntx_mapping[ctrl->val];
+               break;
+       case V4L2_CID_EXPOSURE:
+               ap1302_set_exposure_off(&dev->sd, ctrl->val);
+               break;
+       case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
+               ap1302_set_wb_mode(&dev->sd, ctrl->val);
+               break;
+       case V4L2_CID_ZOOM_ABSOLUTE:
+               ap1302_set_zoom(&dev->sd, ctrl->val);
+               break;
+       case V4L2_CID_COLORFX:
+               ap1302_set_special_effect(&dev->sd, ctrl->val);
+               break;
+       case V4L2_CID_SCENE_MODE:
+               ap1302_set_scene_mode(&dev->sd, ctrl->val);
+               break;
+       case V4L2_CID_POWER_LINE_FREQUENCY:
+               ap1302_set_flicker_freq(&dev->sd, ctrl->val);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int ap1302_g_register(struct v4l2_subdev *sd,
+                            struct v4l2_dbg_register *reg)
+{
+       struct ap1302_device *dev = to_ap1302_device(sd);
+       int ret;
+       u32 reg_val;
+
+       if (reg->size != AP1302_REG16 &&
+           reg->size != AP1302_REG32)
+               return -EINVAL;
+
+       mutex_lock(&dev->input_lock);
+       if (dev->power_on)
+               ret = ap1302_i2c_read_reg(sd, reg->reg, reg->size, &reg_val);
+       else
+               ret = -EIO;
+       mutex_unlock(&dev->input_lock);
+       if (ret)
+               return ret;
+
+       reg->val = reg_val;
+
+       return 0;
+}
+
+static int ap1302_s_register(struct v4l2_subdev *sd,
+                            const struct v4l2_dbg_register *reg)
+{
+       struct ap1302_device *dev = to_ap1302_device(sd);
+       int ret;
+
+       if (reg->size != AP1302_REG16 &&
+           reg->size != AP1302_REG32)
+               return -EINVAL;
+
+       mutex_lock(&dev->input_lock);
+       if (dev->power_on)
+               ret = ap1302_i2c_write_reg(sd, reg->reg, reg->size, reg->val);
+       else
+               ret = -EIO;
+       mutex_unlock(&dev->input_lock);
+       return ret;
+}
+
+static long ap1302_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+       long ret = 0;
+       switch (cmd) {
+       case VIDIOC_DBG_G_REGISTER:
+               ret = ap1302_g_register(sd, arg);
+               break;
+       case VIDIOC_DBG_S_REGISTER:
+               ret = ap1302_s_register(sd, arg);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+       return ret;
+}
+
+static const struct v4l2_ctrl_ops ctrl_ops = {
+       .s_ctrl = ap1302_s_ctrl,
+};
+
+static const char * const ctrl_run_mode_menu[] = {
+       NULL,
+       "Video",
+       "Still capture",
+       "Continuous capture",
+       "Preview",
+};
+
+static const struct v4l2_ctrl_config ctrls[] = {
+       {
+               .ops = &ctrl_ops,
+               .id = V4L2_CID_RUN_MODE,
+               .name = "Run Mode",
+               .type = V4L2_CTRL_TYPE_MENU,
+               .min = 1,
+               .def = 4,
+               .max = 4,
+               .qmenu = ctrl_run_mode_menu,
+       },
+       {
+               .ops = &ctrl_ops,
+               .id = V4L2_CID_EXPOSURE,
+               .name = "Exposure",
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .min = AP1302_MIN_EV,
+               .def = 0,
+               .max = AP1302_MAX_EV,
+               .step = 1,
+       },
+       {
+               .ops = &ctrl_ops,
+               .id = V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE,
+               .name = "White Balance",
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .min = 0,
+               .def = 0,
+               .max = 9,
+               .step = 1,
+       },
+       {
+               .ops = &ctrl_ops,
+               .id = V4L2_CID_ZOOM_ABSOLUTE,
+               .name = "Zoom Absolute",
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .min = 0,
+               .def = 0,
+               .max = 1024,
+               .step = 1,
+       },
+       {
+               .ops = &ctrl_ops,
+               .id = V4L2_CID_COLORFX,
+               .name = "Color Special Effect",
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .min = 0,
+               .def = 0,
+               .max = 15,
+               .step = 1,
+       },
+       {
+               .ops = &ctrl_ops,
+               .id = V4L2_CID_SCENE_MODE,
+               .name = "Scene Mode",
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .min = 0,
+               .def = 0,
+               .max = 13,
+               .step = 1,
+       },
+       {
+               .ops = &ctrl_ops,
+               .id = V4L2_CID_POWER_LINE_FREQUENCY,
+               .name = "Light frequency filter",
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .min = 0,
+               .def = 3,
+               .max = 3,
+               .step = 1,
+       },
+};
+
+static const struct v4l2_subdev_sensor_ops ap1302_sensor_ops = {
+       .g_skip_frames  = ap1302_g_skip_frames,
+};
+
+static const struct v4l2_subdev_video_ops ap1302_video_ops = {
+       .s_stream = ap1302_s_stream,
+       .g_frame_interval = ap1302_g_frame_interval,
+};
+
+static const struct v4l2_subdev_core_ops ap1302_core_ops = {
+       .s_power = ap1302_s_power,
+       .ioctl = ap1302_ioctl,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .g_register = ap1302_g_register,
+       .s_register = ap1302_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_pad_ops ap1302_pad_ops = {
+       .enum_mbus_code = ap1302_enum_mbus_code,
+       .enum_frame_size = ap1302_enum_frame_size,
+       .get_fmt = ap1302_get_fmt,
+       .set_fmt = ap1302_set_fmt,
+};
+
+static const struct v4l2_subdev_ops ap1302_ops = {
+       .core = &ap1302_core_ops,
+       .pad = &ap1302_pad_ops,
+       .video = &ap1302_video_ops,
+       .sensor = &ap1302_sensor_ops
+};
+
+static int ap1302_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct ap1302_device *dev = to_ap1302_device(sd);
+
+       if (dev->platform_data->platform_deinit)
+               dev->platform_data->platform_deinit();
+
+       release_firmware(dev->fw);
+
+       media_entity_cleanup(&dev->sd.entity);
+       dev->platform_data->csi_cfg(sd, 0);
+       v4l2_device_unregister_subdev(sd);
+
+       return 0;
+}
+
+static int ap1302_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct ap1302_device *dev;
+       int ret;
+       unsigned int i;
+
+       dev_info(&client->dev, "ap1302 probe called.\n");
+
+       /* allocate device & init sub device */
+       dev = devm_kzalloc(&client->dev, sizeof(*dev), GFP_KERNEL);
+       if (!dev) {
+               dev_err(&client->dev, "%s: out of memory\n", __func__);
+               return -ENOMEM;
+       }
+
+       mutex_init(&dev->input_lock);
+
+       v4l2_i2c_subdev_init(&(dev->sd), client, &ap1302_ops);
+
+       ret = ap1302_request_firmware(&(dev->sd));
+       if (ret) {
+               dev_err(&client->dev, "Cannot request ap1302 firmware.\n");
+               goto out_free;
+       }
+
+       dev->regmap16 = devm_regmap_init_i2c(client, &ap1302_reg16_config);
+       if (IS_ERR(dev->regmap16)) {
+               ret = PTR_ERR(dev->regmap16);
+               dev_err(&client->dev,
+                       "Failed to allocate 16bit register map: %d\n", ret);
+               return ret;
+       }
+
+       dev->regmap32 = devm_regmap_init_i2c(client, &ap1302_reg32_config);
+       if (IS_ERR(dev->regmap32)) {
+               ret = PTR_ERR(dev->regmap32);
+               dev_err(&client->dev,
+                       "Failed to allocate 32bit register map: %d\n", ret);
+               return ret;
+       }
+
+       if (client->dev.platform_data) {
+               ret = ap1302_s_config(&dev->sd, client->dev.platform_data);
+               if (ret)
+                       goto out_free;
+       }
+
+       dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+       dev->pad.flags = MEDIA_PAD_FL_SOURCE;
+       dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+
+       dev->cntx_res[CONTEXT_PREVIEW].res_num = ARRAY_SIZE(ap1302_preview_res);
+       dev->cntx_res[CONTEXT_PREVIEW].res_table = ap1302_preview_res;
+       dev->cntx_res[CONTEXT_SNAPSHOT].res_num =
+               ARRAY_SIZE(ap1302_snapshot_res);
+       dev->cntx_res[CONTEXT_SNAPSHOT].res_table = ap1302_snapshot_res;
+       dev->cntx_res[CONTEXT_VIDEO].res_num = ARRAY_SIZE(ap1302_video_res);
+       dev->cntx_res[CONTEXT_VIDEO].res_table = ap1302_video_res;
+
+       ret = v4l2_ctrl_handler_init(&dev->ctrl_handler, ARRAY_SIZE(ctrls));
+       if (ret) {
+               ap1302_remove(client);
+               return ret;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(ctrls); i++)
+               v4l2_ctrl_new_custom(&dev->ctrl_handler, &ctrls[i], NULL);
+
+       if (dev->ctrl_handler.error) {
+               ap1302_remove(client);
+               return dev->ctrl_handler.error;
+       }
+
+       /* Use same lock for controls as for everything else. */
+       dev->ctrl_handler.lock = &dev->input_lock;
+       dev->sd.ctrl_handler = &dev->ctrl_handler;
+       v4l2_ctrl_handler_setup(&dev->ctrl_handler);
+
+       dev->run_mode = v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_RUN_MODE);
+       v4l2_ctrl_s_ctrl(dev->run_mode, ATOMISP_RUN_MODE_PREVIEW);
+
+       ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad);
+       if (ret)
+               ap1302_remove(client);
+       return ret;
+out_free:
+       v4l2_device_unregister_subdev(&dev->sd);
+       return ret;
+}
+
+static const struct i2c_device_id ap1302_id[] = {
+       {AP1302_NAME, 0},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, ap1302_id);
+
+static struct i2c_driver ap1302_driver = {
+       .driver = {
+               .name = AP1302_NAME,
+       },
+       .probe = ap1302_probe,
+       .remove = ap1302_remove,
+       .id_table = ap1302_id,
+};
+
+module_i2c_driver(ap1302_driver);
+
+MODULE_AUTHOR("Tianshu Qiu <tian.shu.qiu@intel.com>");
+MODULE_DESCRIPTION("AP1302 Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c
new file mode 100644 (file)
index 0000000..35ed51f
--- /dev/null
@@ -0,0 +1,1490 @@
+/*
+ * Support for GalaxyCore GC0310 VGA camera sensor.
+ *
+ * Copyright (c) 2013 Intel Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kmod.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/moduleparam.h>
+#include <media/v4l2-device.h>
+#include <linux/io.h>
+#include "../include/linux/atomisp_gmin_platform.h"
+
+#include "gc0310.h"
+
+/* i2c read/write stuff */
+static int gc0310_read_reg(struct i2c_client *client,
+                          u16 data_length, u8 reg, u8 *val)
+{
+       int err;
+       struct i2c_msg msg[2];
+       unsigned char data[1];
+
+       if (!client->adapter) {
+               dev_err(&client->dev, "%s error, no client->adapter\n",
+                       __func__);
+               return -ENODEV;
+       }
+
+       if (data_length != GC0310_8BIT) {
+               dev_err(&client->dev, "%s error, invalid data length\n",
+                       __func__);
+               return -EINVAL;
+       }
+
+       memset(msg, 0, sizeof(msg));
+
+       msg[0].addr = client->addr;
+       msg[0].flags = 0;
+       msg[0].len = I2C_MSG_LENGTH;
+       msg[0].buf = data;
+
+       /* high byte goes out first */
+       data[0] = (u8)(reg & 0xff);
+
+       msg[1].addr = client->addr;
+       msg[1].len = data_length;
+       msg[1].flags = I2C_M_RD;
+       msg[1].buf = data;
+
+       err = i2c_transfer(client->adapter, msg, 2);
+       if (err != 2) {
+               if (err >= 0)
+                       err = -EIO;
+               dev_err(&client->dev,
+                       "read from offset 0x%x error %d", reg, err);
+               return err;
+       }
+
+       *val = 0;
+       /* high byte comes first */
+       if (data_length == GC0310_8BIT)
+               *val = (u8)data[0];
+
+       return 0;
+}
+
+static int gc0310_i2c_write(struct i2c_client *client, u16 len, u8 *data)
+{
+       struct i2c_msg msg;
+       const int num_msg = 1;
+       int ret;
+
+       msg.addr = client->addr;
+       msg.flags = 0;
+       msg.len = len;
+       msg.buf = data;
+       ret = i2c_transfer(client->adapter, &msg, 1);
+
+       return ret == num_msg ? 0 : -EIO;
+}
+
+static int gc0310_write_reg(struct i2c_client *client, u16 data_length,
+                                                       u8 reg, u8 val)
+{
+       int ret;
+       unsigned char data[2] = {0};
+       u8 *wreg = (u8 *)data;
+       const u16 len = data_length + sizeof(u8); /* 8-bit address + data */
+
+       if (data_length != GC0310_8BIT) {
+               dev_err(&client->dev,
+                       "%s error, invalid data_length\n", __func__);
+               return -EINVAL;
+       }
+
+       /* high byte goes out first */
+       *wreg = (u8)(reg & 0xff);
+
+       if (data_length == GC0310_8BIT)
+               data[1] = (u8)(val);
+
+       ret = gc0310_i2c_write(client, len, data);
+       if (ret)
+               dev_err(&client->dev,
+                       "write error: wrote 0x%x to offset 0x%x error %d",
+                       val, reg, ret);
+
+       return ret;
+}
+
+/*
+ * gc0310_write_reg_array - Initializes a list of GC0310 registers
+ * @client: i2c driver client structure
+ * @reglist: list of registers to be written
+ *
+ * This function initializes a list of registers. When consecutive addresses
+ * are found in a row on the list, this function creates a buffer and sends
+ * consecutive data in a single i2c_transfer().
+ *
+ * __gc0310_flush_reg_array, __gc0310_buf_reg_array() and
+ * __gc0310_write_reg_is_consecutive() are internal functions to
+ * gc0310_write_reg_array_fast() and should be not used anywhere else.
+ *
+ */
+
+static int __gc0310_flush_reg_array(struct i2c_client *client,
+                                   struct gc0310_write_ctrl *ctrl)
+{
+       u16 size;
+
+       if (ctrl->index == 0)
+               return 0;
+
+       size = sizeof(u8) + ctrl->index; /* 8-bit address + data */
+       ctrl->buffer.addr = (u8)(ctrl->buffer.addr);
+       ctrl->index = 0;
+
+       return gc0310_i2c_write(client, size, (u8 *)&ctrl->buffer);
+}
+
+static int __gc0310_buf_reg_array(struct i2c_client *client,
+                                 struct gc0310_write_ctrl *ctrl,
+                                 const struct gc0310_reg *next)
+{
+       int size;
+
+       switch (next->type) {
+       case GC0310_8BIT:
+               size = 1;
+               ctrl->buffer.data[ctrl->index] = (u8)next->val;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* When first item is added, we need to store its starting address */
+       if (ctrl->index == 0)
+               ctrl->buffer.addr = next->reg;
+
+       ctrl->index += size;
+
+       /*
+        * Buffer cannot guarantee free space for u32? Better flush it to avoid
+        * possible lack of memory for next item.
+        */
+       if (ctrl->index + sizeof(u8) >= GC0310_MAX_WRITE_BUF_SIZE)
+               return __gc0310_flush_reg_array(client, ctrl);
+
+       return 0;
+}
+
+static int __gc0310_write_reg_is_consecutive(struct i2c_client *client,
+                                            struct gc0310_write_ctrl *ctrl,
+                                            const struct gc0310_reg *next)
+{
+       if (ctrl->index == 0)
+               return 1;
+
+       return ctrl->buffer.addr + ctrl->index == next->reg;
+}
+
+static int gc0310_write_reg_array(struct i2c_client *client,
+                                 const struct gc0310_reg *reglist)
+{
+       const struct gc0310_reg *next = reglist;
+       struct gc0310_write_ctrl ctrl;
+       int err;
+
+       ctrl.index = 0;
+       for (; next->type != GC0310_TOK_TERM; next++) {
+               switch (next->type & GC0310_TOK_MASK) {
+               case GC0310_TOK_DELAY:
+                       err = __gc0310_flush_reg_array(client, &ctrl);
+                       if (err)
+                               return err;
+                       msleep(next->val);
+                       break;
+               default:
+                       /*
+                        * If next address is not consecutive, data needs to be
+                        * flushed before proceed.
+                        */
+                       if (!__gc0310_write_reg_is_consecutive(client, &ctrl,
+                                                               next)) {
+                               err = __gc0310_flush_reg_array(client, &ctrl);
+                               if (err)
+                                       return err;
+                       }
+                       err = __gc0310_buf_reg_array(client, &ctrl, next);
+                       if (err) {
+                               dev_err(&client->dev, "%s: write error, aborted\n",
+                                        __func__);
+                               return err;
+                       }
+                       break;
+               }
+       }
+
+       return __gc0310_flush_reg_array(client, &ctrl);
+}
+static int gc0310_g_focal(struct v4l2_subdev *sd, s32 *val)
+{
+       *val = (GC0310_FOCAL_LENGTH_NUM << 16) | GC0310_FOCAL_LENGTH_DEM;
+       return 0;
+}
+
+static int gc0310_g_fnumber(struct v4l2_subdev *sd, s32 *val)
+{
+       /*const f number for imx*/
+       *val = (GC0310_F_NUMBER_DEFAULT_NUM << 16) | GC0310_F_NUMBER_DEM;
+       return 0;
+}
+
+static int gc0310_g_fnumber_range(struct v4l2_subdev *sd, s32 *val)
+{
+       *val = (GC0310_F_NUMBER_DEFAULT_NUM << 24) |
+               (GC0310_F_NUMBER_DEM << 16) |
+               (GC0310_F_NUMBER_DEFAULT_NUM << 8) | GC0310_F_NUMBER_DEM;
+       return 0;
+}
+
+static int gc0310_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val)
+{
+       struct gc0310_device *dev = to_gc0310_sensor(sd);
+
+       *val = gc0310_res[dev->fmt_idx].bin_factor_x;
+
+       return 0;
+}
+
+static int gc0310_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val)
+{
+       struct gc0310_device *dev = to_gc0310_sensor(sd);
+
+       *val = gc0310_res[dev->fmt_idx].bin_factor_y;
+
+       return 0;
+}
+
+static int gc0310_get_intg_factor(struct i2c_client *client,
+                               struct camera_mipi_info *info,
+                               const struct gc0310_resolution *res)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct gc0310_device *dev = to_gc0310_sensor(sd);
+       struct atomisp_sensor_mode_data *buf = &info->data;
+       u16 val;
+       u8 reg_val;
+       int ret;
+       unsigned int hori_blanking;
+       unsigned int vert_blanking;
+       unsigned int sh_delay;
+
+       if (!info)
+               return -EINVAL;
+
+       /* pixel clock calculattion */
+       dev->vt_pix_clk_freq_mhz = 14400000; // 16.8MHz
+       buf->vt_pix_clk_freq_mhz = dev->vt_pix_clk_freq_mhz;
+       pr_info("vt_pix_clk_freq_mhz=%d\n", buf->vt_pix_clk_freq_mhz);
+
+       /* get integration time */
+       buf->coarse_integration_time_min = GC0310_COARSE_INTG_TIME_MIN;
+       buf->coarse_integration_time_max_margin =
+                                       GC0310_COARSE_INTG_TIME_MAX_MARGIN;
+
+       buf->fine_integration_time_min = GC0310_FINE_INTG_TIME_MIN;
+       buf->fine_integration_time_max_margin =
+                                       GC0310_FINE_INTG_TIME_MAX_MARGIN;
+
+       buf->fine_integration_time_def = GC0310_FINE_INTG_TIME_MIN;
+       buf->read_mode = res->bin_mode;
+
+       /* get the cropping and output resolution to ISP for this mode. */
+       /* Getting crop_horizontal_start */
+       ret =  gc0310_read_reg(client, GC0310_8BIT,
+                                       GC0310_H_CROP_START_H, &reg_val);
+       if (ret)
+               return ret;
+       val = (reg_val & 0xFF) << 8;
+       ret =  gc0310_read_reg(client, GC0310_8BIT,
+                                       GC0310_H_CROP_START_L, &reg_val);
+       if (ret)
+               return ret;
+       buf->crop_horizontal_start = val | (reg_val & 0xFF);
+       pr_info("crop_horizontal_start=%d\n", buf->crop_horizontal_start);
+
+       /* Getting crop_vertical_start */
+       ret =  gc0310_read_reg(client, GC0310_8BIT,
+                                       GC0310_V_CROP_START_H, &reg_val);
+       if (ret)
+               return ret;
+       val = (reg_val & 0xFF) << 8;
+       ret =  gc0310_read_reg(client, GC0310_8BIT,
+                                       GC0310_V_CROP_START_L, &reg_val);
+       if (ret)
+               return ret;
+       buf->crop_vertical_start = val | (reg_val & 0xFF);
+       pr_info("crop_vertical_start=%d\n", buf->crop_vertical_start);
+
+       /* Getting output_width */
+       ret = gc0310_read_reg(client, GC0310_8BIT,
+                                       GC0310_H_OUTSIZE_H, &reg_val);
+       if (ret)
+               return ret;
+       val = (reg_val & 0xFF) << 8;
+       ret = gc0310_read_reg(client, GC0310_8BIT,
+                                       GC0310_H_OUTSIZE_L, &reg_val);
+       if (ret)
+               return ret;
+       buf->output_width = val | (reg_val & 0xFF);
+       pr_info("output_width=%d\n", buf->output_width);
+
+       /* Getting output_height */
+       ret = gc0310_read_reg(client, GC0310_8BIT,
+                                       GC0310_V_OUTSIZE_H, &reg_val);
+       if (ret)
+               return ret;
+       val = (reg_val & 0xFF) << 8;
+       ret = gc0310_read_reg(client, GC0310_8BIT,
+                                       GC0310_V_OUTSIZE_L, &reg_val);
+       if (ret)
+               return ret;
+       buf->output_height = val | (reg_val & 0xFF);
+       pr_info("output_height=%d\n", buf->output_height);
+
+       buf->crop_horizontal_end = buf->crop_horizontal_start + buf->output_width - 1;
+       buf->crop_vertical_end = buf->crop_vertical_start + buf->output_height - 1;
+       pr_info("crop_horizontal_end=%d\n", buf->crop_horizontal_end);
+       pr_info("crop_vertical_end=%d\n", buf->crop_vertical_end);
+
+       /* Getting line_length_pck */
+       ret = gc0310_read_reg(client, GC0310_8BIT,
+                                       GC0310_H_BLANKING_H, &reg_val);
+       if (ret)
+               return ret;
+       val = (reg_val & 0xFF) << 8;
+       ret = gc0310_read_reg(client, GC0310_8BIT,
+                                       GC0310_H_BLANKING_L, &reg_val);
+       if (ret)
+               return ret;
+       hori_blanking = val | (reg_val & 0xFF);
+       ret = gc0310_read_reg(client, GC0310_8BIT,
+                                       GC0310_SH_DELAY, &reg_val);
+       if (ret)
+               return ret;
+       sh_delay = reg_val;
+       buf->line_length_pck = buf->output_width + hori_blanking + sh_delay + 4;
+       pr_info("hori_blanking=%d sh_delay=%d line_length_pck=%d\n", hori_blanking, sh_delay, buf->line_length_pck);
+
+       /* Getting frame_length_lines */
+       ret = gc0310_read_reg(client, GC0310_8BIT,
+                                       GC0310_V_BLANKING_H, &reg_val);
+       if (ret)
+               return ret;
+       val = (reg_val & 0xFF) << 8;
+       ret = gc0310_read_reg(client, GC0310_8BIT,
+                                       GC0310_V_BLANKING_L, &reg_val);
+       if (ret)
+               return ret;
+       vert_blanking = val | (reg_val & 0xFF);
+       buf->frame_length_lines = buf->output_height + vert_blanking;
+       pr_info("vert_blanking=%d frame_length_lines=%d\n", vert_blanking, buf->frame_length_lines);
+
+       buf->binning_factor_x = res->bin_factor_x ?
+                                       res->bin_factor_x : 1;
+       buf->binning_factor_y = res->bin_factor_y ?
+                                       res->bin_factor_y : 1;
+       return 0;
+}
+
+static int gc0310_set_gain(struct v4l2_subdev *sd, int gain)
+
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret;
+       u8 again, dgain;
+
+       if (gain < 0x20)
+               gain = 0x20;
+       if (gain > 0x80)
+               gain = 0x80;
+
+       if (gain >= 0x20 && gain < 0x40) {
+               again = 0x0; /* sqrt(2) */
+               dgain = gain;
+       } else {
+               again = 0x2; /* 2 * sqrt(2) */
+               dgain = gain / 2;
+       }
+
+       pr_info("gain=0x%x again=0x%x dgain=0x%x\n", gain, again, dgain);
+
+       /* set analog gain */
+       ret = gc0310_write_reg(client, GC0310_8BIT,
+                                       GC0310_AGC_ADJ, again);
+       if (ret)
+               return ret;
+
+       /* set digital gain */
+       ret = gc0310_write_reg(client, GC0310_8BIT,
+                                       GC0310_DGC_ADJ, dgain);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int __gc0310_set_exposure(struct v4l2_subdev *sd, int coarse_itg,
+                                int gain, int digitgain)
+
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret;
+
+       pr_info("coarse_itg=%d gain=%d digitgain=%d\n", coarse_itg, gain, digitgain);
+
+       /* set exposure */
+       ret = gc0310_write_reg(client, GC0310_8BIT,
+                                       GC0310_AEC_PK_EXPO_L,
+                                       coarse_itg & 0xff);
+       if (ret)
+               return ret;
+
+       ret = gc0310_write_reg(client, GC0310_8BIT,
+                                       GC0310_AEC_PK_EXPO_H,
+                                       (coarse_itg >> 8) & 0x0f);
+       if (ret)
+               return ret;
+
+       ret = gc0310_set_gain(sd, gain);
+       if (ret)
+               return ret;
+
+       return ret;
+}
+
+static int gc0310_set_exposure(struct v4l2_subdev *sd, int exposure,
+       int gain, int digitgain)
+{
+       struct gc0310_device *dev = to_gc0310_sensor(sd);
+       int ret;
+
+       mutex_lock(&dev->input_lock);
+       ret = __gc0310_set_exposure(sd, exposure, gain, digitgain);
+       mutex_unlock(&dev->input_lock);
+
+       return ret;
+}
+
+static long gc0310_s_exposure(struct v4l2_subdev *sd,
+                              struct atomisp_exposure *exposure)
+{
+       int exp = exposure->integration_time[0];
+       int gain = exposure->gain[0];
+       int digitgain = exposure->gain[1];
+
+       /* we should not accept the invalid value below. */
+       if (gain == 0) {
+               struct i2c_client *client = v4l2_get_subdevdata(sd);
+               v4l2_err(client, "%s: invalid value\n", __func__);
+               return -EINVAL;
+       }
+
+       return gc0310_set_exposure(sd, exp, gain, digitgain);
+}
+
+/* TO DO */
+static int gc0310_v_flip(struct v4l2_subdev *sd, s32 value)
+{
+       return 0;
+}
+
+/* TO DO */
+static int gc0310_h_flip(struct v4l2_subdev *sd, s32 value)
+{
+       return 0;
+}
+
+static long gc0310_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+
+       switch (cmd) {
+       case ATOMISP_IOC_S_EXPOSURE:
+               return gc0310_s_exposure(sd, arg);
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/* This returns the exposure time being used. This should only be used
+ * for filling in EXIF data, not for actual image processing.
+ */
+static int gc0310_q_exposure(struct v4l2_subdev *sd, s32 *value)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       u8 reg_v;
+       int ret;
+
+       /* get exposure */
+       ret = gc0310_read_reg(client, GC0310_8BIT,
+                                       GC0310_AEC_PK_EXPO_L,
+                                       &reg_v);
+       if (ret)
+               goto err;
+
+       *value = reg_v;
+       ret = gc0310_read_reg(client, GC0310_8BIT,
+                                       GC0310_AEC_PK_EXPO_H,
+                                       &reg_v);
+       if (ret)
+               goto err;
+
+       *value = *value + (reg_v << 8);
+err:
+       return ret;
+}
+
+static int gc0310_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct gc0310_device *dev =
+           container_of(ctrl->handler, struct gc0310_device, ctrl_handler);
+       struct i2c_client *client = v4l2_get_subdevdata(&dev->sd);
+       int ret = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_VFLIP:
+               dev_dbg(&client->dev, "%s: CID_VFLIP:%d.\n",
+                       __func__, ctrl->val);
+               ret = gc0310_v_flip(&dev->sd, ctrl->val);
+               break;
+       case V4L2_CID_HFLIP:
+               dev_dbg(&client->dev, "%s: CID_HFLIP:%d.\n",
+                       __func__, ctrl->val);
+               ret = gc0310_h_flip(&dev->sd, ctrl->val);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+       return ret;
+}
+
+static int gc0310_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct gc0310_device *dev =
+           container_of(ctrl->handler, struct gc0310_device, ctrl_handler);
+       int ret = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE_ABSOLUTE:
+               ret = gc0310_q_exposure(&dev->sd, &ctrl->val);
+               break;
+       case V4L2_CID_FOCAL_ABSOLUTE:
+               ret = gc0310_g_focal(&dev->sd, &ctrl->val);
+               break;
+       case V4L2_CID_FNUMBER_ABSOLUTE:
+               ret = gc0310_g_fnumber(&dev->sd, &ctrl->val);
+               break;
+       case V4L2_CID_FNUMBER_RANGE:
+               ret = gc0310_g_fnumber_range(&dev->sd, &ctrl->val);
+               break;
+       case V4L2_CID_BIN_FACTOR_HORZ:
+               ret = gc0310_g_bin_factor_x(&dev->sd, &ctrl->val);
+               break;
+       case V4L2_CID_BIN_FACTOR_VERT:
+               ret = gc0310_g_bin_factor_y(&dev->sd, &ctrl->val);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static const struct v4l2_ctrl_ops ctrl_ops = {
+       .s_ctrl = gc0310_s_ctrl,
+       .g_volatile_ctrl = gc0310_g_volatile_ctrl
+};
+
+struct v4l2_ctrl_config gc0310_controls[] = {
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_EXPOSURE_ABSOLUTE,
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .name = "exposure",
+        .min = 0x0,
+        .max = 0xffff,
+        .step = 0x01,
+        .def = 0x00,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_VFLIP,
+        .type = V4L2_CTRL_TYPE_BOOLEAN,
+        .name = "Flip",
+        .min = 0,
+        .max = 1,
+        .step = 1,
+        .def = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_HFLIP,
+        .type = V4L2_CTRL_TYPE_BOOLEAN,
+        .name = "Mirror",
+        .min = 0,
+        .max = 1,
+        .step = 1,
+        .def = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_FOCAL_ABSOLUTE,
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .name = "focal length",
+        .min = GC0310_FOCAL_LENGTH_DEFAULT,
+        .max = GC0310_FOCAL_LENGTH_DEFAULT,
+        .step = 0x01,
+        .def = GC0310_FOCAL_LENGTH_DEFAULT,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_FNUMBER_ABSOLUTE,
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .name = "f-number",
+        .min = GC0310_F_NUMBER_DEFAULT,
+        .max = GC0310_F_NUMBER_DEFAULT,
+        .step = 0x01,
+        .def = GC0310_F_NUMBER_DEFAULT,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_FNUMBER_RANGE,
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .name = "f-number range",
+        .min = GC0310_F_NUMBER_RANGE,
+        .max = GC0310_F_NUMBER_RANGE,
+        .step = 0x01,
+        .def = GC0310_F_NUMBER_RANGE,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_BIN_FACTOR_HORZ,
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .name = "horizontal binning factor",
+        .min = 0,
+        .max = GC0310_BIN_FACTOR_MAX,
+        .step = 1,
+        .def = 0,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_BIN_FACTOR_VERT,
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .name = "vertical binning factor",
+        .min = 0,
+        .max = GC0310_BIN_FACTOR_MAX,
+        .step = 1,
+        .def = 0,
+        .flags = 0,
+        },
+};
+
+static int gc0310_init(struct v4l2_subdev *sd)
+{
+       int ret;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct gc0310_device *dev = to_gc0310_sensor(sd);
+
+       pr_info("%s S\n", __func__);
+       mutex_lock(&dev->input_lock);
+
+       /* set inital registers */
+       ret  = gc0310_write_reg_array(client, gc0310_reset_register);
+
+       /* restore settings */
+       gc0310_res = gc0310_res_preview;
+       N_RES = N_RES_PREVIEW;
+
+       mutex_unlock(&dev->input_lock);
+
+       pr_info("%s E\n", __func__);
+       return 0;
+}
+
+static int power_ctrl(struct v4l2_subdev *sd, bool flag)
+{
+       int ret = 0;
+       struct gc0310_device *dev = to_gc0310_sensor(sd);
+       if (!dev || !dev->platform_data)
+               return -ENODEV;
+
+       /* Non-gmin platforms use the legacy callback */
+       if (dev->platform_data->power_ctrl)
+               return dev->platform_data->power_ctrl(sd, flag);
+
+       if (flag) {
+               /* The upstream module driver (written to Crystal
+                * Cove) had this logic to pulse the rails low first.
+                * This appears to break things on the MRD7 with the
+                * X-Powers PMIC...
+                *
+                *     ret = dev->platform_data->v1p8_ctrl(sd, 0);
+                *     ret |= dev->platform_data->v2p8_ctrl(sd, 0);
+                *     mdelay(50);
+                */
+               ret |= dev->platform_data->v1p8_ctrl(sd, 1);
+               ret |= dev->platform_data->v2p8_ctrl(sd, 1);
+               usleep_range(10000, 15000);
+       }
+
+       if (!flag || ret) {
+               ret |= dev->platform_data->v1p8_ctrl(sd, 0);
+               ret |= dev->platform_data->v2p8_ctrl(sd, 0);
+       }
+       return ret;
+}
+
+static int gpio_ctrl(struct v4l2_subdev *sd, bool flag)
+{
+       int ret;
+       struct gc0310_device *dev = to_gc0310_sensor(sd);
+
+       if (!dev || !dev->platform_data)
+               return -ENODEV;
+
+       /* Non-gmin platforms use the legacy callback */
+       if (dev->platform_data->gpio_ctrl)
+               return dev->platform_data->gpio_ctrl(sd, flag);
+
+       /* GPIO0 == "reset" (active low), GPIO1 == "power down" */
+       if (flag) {
+               /* Pulse reset, then release power down */
+               ret = dev->platform_data->gpio0_ctrl(sd, 0);
+               usleep_range(5000, 10000);
+               ret |= dev->platform_data->gpio0_ctrl(sd, 1);
+               usleep_range(10000, 15000);
+               ret |= dev->platform_data->gpio1_ctrl(sd, 0);
+               usleep_range(10000, 15000);
+       } else {
+               ret = dev->platform_data->gpio1_ctrl(sd, 1);
+               ret |= dev->platform_data->gpio0_ctrl(sd, 0);
+       }
+       return ret;
+}
+
+
+static int power_down(struct v4l2_subdev *sd);
+
+static int power_up(struct v4l2_subdev *sd)
+{
+       struct gc0310_device *dev = to_gc0310_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret;
+
+       pr_info("%s S\n", __func__);
+       if (!dev->platform_data) {
+               dev_err(&client->dev,
+                       "no camera_sensor_platform_data");
+               return -ENODEV;
+       }
+
+       /* power control */
+       ret = power_ctrl(sd, 1);
+       if (ret)
+               goto fail_power;
+
+       /* flis clock control */
+       ret = dev->platform_data->flisclk_ctrl(sd, 1);
+       if (ret)
+               goto fail_clk;
+
+       /* gpio ctrl */
+       ret = gpio_ctrl(sd, 1);
+       if (ret) {
+               ret = gpio_ctrl(sd, 1);
+               if (ret)
+                       goto fail_gpio;
+       }
+
+       msleep(100);
+
+       pr_info("%s E\n", __func__);
+       return 0;
+
+fail_gpio:
+       dev->platform_data->flisclk_ctrl(sd, 0);
+fail_clk:
+       power_ctrl(sd, 0);
+fail_power:
+       dev_err(&client->dev, "sensor power-up failed\n");
+
+       return ret;
+}
+
+static int power_down(struct v4l2_subdev *sd)
+{
+       struct gc0310_device *dev = to_gc0310_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret = 0;
+
+       if (!dev->platform_data) {
+               dev_err(&client->dev,
+                       "no camera_sensor_platform_data");
+               return -ENODEV;
+       }
+
+       /* gpio ctrl */
+       ret = gpio_ctrl(sd, 0);
+       if (ret) {
+               ret = gpio_ctrl(sd, 0);
+               if (ret)
+                       dev_err(&client->dev, "gpio failed 2\n");
+       }
+
+       ret = dev->platform_data->flisclk_ctrl(sd, 0);
+       if (ret)
+               dev_err(&client->dev, "flisclk failed\n");
+
+       /* power control */
+       ret = power_ctrl(sd, 0);
+       if (ret)
+               dev_err(&client->dev, "vprog failed.\n");
+
+       return ret;
+}
+
+static int gc0310_s_power(struct v4l2_subdev *sd, int on)
+{
+       int ret;
+       if (on == 0)
+               return power_down(sd);
+       else {
+               ret = power_up(sd);
+               if (!ret)
+                       return gc0310_init(sd);
+       }
+       return ret;
+}
+
+/*
+ * distance - calculate the distance
+ * @res: resolution
+ * @w: width
+ * @h: height
+ *
+ * Get the gap between resolution and w/h.
+ * res->width/height smaller than w/h wouldn't be considered.
+ * Returns the value of gap or -1 if fail.
+ */
+#define LARGEST_ALLOWED_RATIO_MISMATCH 800
+static int distance(struct gc0310_resolution *res, u32 w, u32 h)
+{
+       unsigned int w_ratio = (res->width << 13) / w;
+       unsigned int h_ratio;
+       int match;
+
+       if (h == 0)
+               return -1;
+       h_ratio = (res->height << 13) / h;
+       if (h_ratio == 0)
+               return -1;
+       match   = abs(((w_ratio << 13) / h_ratio) - ((int)8192));
+
+       if ((w_ratio < (int)8192) || (h_ratio < (int)8192)  ||
+               (match > LARGEST_ALLOWED_RATIO_MISMATCH))
+               return -1;
+
+       return w_ratio + h_ratio;
+}
+
+/* Return the nearest higher resolution index */
+static int nearest_resolution_index(int w, int h)
+{
+       int i;
+       int idx = -1;
+       int dist;
+       int min_dist = INT_MAX;
+       struct gc0310_resolution *tmp_res = NULL;
+
+       for (i = 0; i < N_RES; i++) {
+               tmp_res = &gc0310_res[i];
+               dist = distance(tmp_res, w, h);
+               if (dist == -1)
+                       continue;
+               if (dist < min_dist) {
+                       min_dist = dist;
+                       idx = i;
+               }
+       }
+
+       return idx;
+}
+
+static int get_resolution_index(int w, int h)
+{
+       int i;
+
+       for (i = 0; i < N_RES; i++) {
+               if (w != gc0310_res[i].width)
+                       continue;
+               if (h != gc0310_res[i].height)
+                       continue;
+
+               return i;
+       }
+
+       return -1;
+}
+
+
+/* TODO: remove it. */
+static int startup(struct v4l2_subdev *sd)
+{
+       struct gc0310_device *dev = to_gc0310_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret = 0;
+
+       pr_info("%s S\n", __func__);
+
+       ret = gc0310_write_reg_array(client, gc0310_res[dev->fmt_idx].regs);
+       if (ret) {
+               dev_err(&client->dev, "gc0310 write register err.\n");
+               return ret;
+       }
+
+       pr_info("%s E\n", __func__);
+       return ret;
+}
+
+static int gc0310_set_fmt(struct v4l2_subdev *sd,
+                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_format *format)
+{
+       struct v4l2_mbus_framefmt *fmt = &format->format;
+       struct gc0310_device *dev = to_gc0310_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct camera_mipi_info *gc0310_info = NULL;
+       int ret = 0;
+       int idx = 0;
+       pr_info("%s S\n", __func__);
+
+       if (format->pad)
+               return -EINVAL;
+
+       if (!fmt)
+               return -EINVAL;
+
+       gc0310_info = v4l2_get_subdev_hostdata(sd);
+       if (!gc0310_info)
+               return -EINVAL;
+
+       mutex_lock(&dev->input_lock);
+
+       idx = nearest_resolution_index(fmt->width, fmt->height);
+       if (idx == -1) {
+               /* return the largest resolution */
+               fmt->width = gc0310_res[N_RES - 1].width;
+               fmt->height = gc0310_res[N_RES - 1].height;
+       } else {
+               fmt->width = gc0310_res[idx].width;
+               fmt->height = gc0310_res[idx].height;
+       }
+       fmt->code = MEDIA_BUS_FMT_SGRBG8_1X8;
+
+       if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+               cfg->try_fmt = *fmt;
+               mutex_unlock(&dev->input_lock);
+               return 0;
+       }
+
+       dev->fmt_idx = get_resolution_index(fmt->width, fmt->height);
+       if (dev->fmt_idx == -1) {
+               dev_err(&client->dev, "get resolution fail\n");
+               mutex_unlock(&dev->input_lock);
+               return -EINVAL;
+       }
+
+       printk("%s: before gc0310_write_reg_array %s\n", __FUNCTION__,
+              gc0310_res[dev->fmt_idx].desc);
+       ret = startup(sd);
+       if (ret) {
+               dev_err(&client->dev, "gc0310 startup err\n");
+               goto err;
+       }
+
+       ret = gc0310_get_intg_factor(client, gc0310_info,
+                                    &gc0310_res[dev->fmt_idx]);
+       if (ret) {
+               dev_err(&client->dev, "failed to get integration_factor\n");
+               goto err;
+       }
+
+       pr_info("%s E\n", __func__);
+err:
+       mutex_unlock(&dev->input_lock);
+       return ret;
+}
+
+static int gc0310_get_fmt(struct v4l2_subdev *sd,
+                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_format *format)
+{
+       struct v4l2_mbus_framefmt *fmt = &format->format;
+       struct gc0310_device *dev = to_gc0310_sensor(sd);
+
+       if (format->pad)
+               return -EINVAL;
+
+       if (!fmt)
+               return -EINVAL;
+
+       fmt->width = gc0310_res[dev->fmt_idx].width;
+       fmt->height = gc0310_res[dev->fmt_idx].height;
+       fmt->code = MEDIA_BUS_FMT_SGRBG8_1X8;
+
+       return 0;
+}
+
+static int gc0310_detect(struct i2c_client *client)
+{
+       struct i2c_adapter *adapter = client->adapter;
+       u8 high, low;
+       int ret;
+       u16 id;
+
+       pr_info("%s S\n", __func__);
+       if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
+               return -ENODEV;
+
+       ret = gc0310_read_reg(client, GC0310_8BIT,
+                                       GC0310_SC_CMMN_CHIP_ID_H, &high);
+       if (ret) {
+               dev_err(&client->dev, "read sensor_id_high failed\n");
+               return -ENODEV;
+       }
+       ret = gc0310_read_reg(client, GC0310_8BIT,
+                                       GC0310_SC_CMMN_CHIP_ID_L, &low);
+       if (ret) {
+               dev_err(&client->dev, "read sensor_id_low failed\n");
+               return -ENODEV;
+       }
+       id = ((((u16) high) << 8) | (u16) low);
+       pr_info("sensor ID = 0x%x\n", id);
+
+       if (id != GC0310_ID) {
+               dev_err(&client->dev, "sensor ID error, read id = 0x%x, target id = 0x%x\n", id, GC0310_ID);
+               return -ENODEV;
+       }
+
+       dev_dbg(&client->dev, "detect gc0310 success\n");
+
+       pr_info("%s E\n", __func__);
+
+       return 0;
+}
+
+static int gc0310_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct gc0310_device *dev = to_gc0310_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret;
+
+       pr_info("%s S enable=%d\n", __func__, enable);
+       mutex_lock(&dev->input_lock);
+
+       if (enable) {
+               /* enable per frame MIPI and sensor ctrl reset  */
+               ret = gc0310_write_reg(client, GC0310_8BIT,
+                                               0xFE, 0x30);
+               if (ret) {
+                       mutex_unlock(&dev->input_lock);
+                       return ret;
+               }
+       }
+
+       ret = gc0310_write_reg(client, GC0310_8BIT,
+                               GC0310_RESET_RELATED, GC0310_REGISTER_PAGE_3);
+       if (ret) {
+               mutex_unlock(&dev->input_lock);
+               return ret;
+       }
+
+       ret = gc0310_write_reg(client, GC0310_8BIT, GC0310_SW_STREAM,
+                               enable ? GC0310_START_STREAMING :
+                               GC0310_STOP_STREAMING);
+       if (ret) {
+               mutex_unlock(&dev->input_lock);
+               return ret;
+       }
+
+       ret = gc0310_write_reg(client, GC0310_8BIT,
+                               GC0310_RESET_RELATED, GC0310_REGISTER_PAGE_0);
+       if (ret) {
+               mutex_unlock(&dev->input_lock);
+               return ret;
+       }
+
+       mutex_unlock(&dev->input_lock);
+       pr_info("%s E\n", __func__);
+       return ret;
+}
+
+
+static int gc0310_s_config(struct v4l2_subdev *sd,
+                          int irq, void *platform_data)
+{
+       struct gc0310_device *dev = to_gc0310_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret = 0;
+
+       pr_info("%s S\n", __func__);
+       if (!platform_data)
+               return -ENODEV;
+
+       dev->platform_data =
+               (struct camera_sensor_platform_data *)platform_data;
+
+       mutex_lock(&dev->input_lock);
+       if (dev->platform_data->platform_init) {
+               ret = dev->platform_data->platform_init(client);
+               if (ret) {
+                       dev_err(&client->dev, "platform init err\n");
+                       goto platform_init_failed;
+               }
+       }
+       /* power off the module, then power on it in future
+        * as first power on by board may not fulfill the
+        * power on sequqence needed by the module
+        */
+       ret = power_down(sd);
+       if (ret) {
+               dev_err(&client->dev, "gc0310 power-off err.\n");
+               goto fail_power_off;
+       }
+
+       ret = power_up(sd);
+       if (ret) {
+               dev_err(&client->dev, "gc0310 power-up err.\n");
+               goto fail_power_on;
+       }
+
+       ret = dev->platform_data->csi_cfg(sd, 1);
+       if (ret)
+               goto fail_csi_cfg;
+
+       /* config & detect sensor */
+       ret = gc0310_detect(client);
+       if (ret) {
+               dev_err(&client->dev, "gc0310_detect err s_config.\n");
+               goto fail_csi_cfg;
+       }
+
+       /* turn off sensor, after probed */
+       ret = power_down(sd);
+       if (ret) {
+               dev_err(&client->dev, "gc0310 power-off err.\n");
+               goto fail_csi_cfg;
+       }
+       mutex_unlock(&dev->input_lock);
+
+       pr_info("%s E\n", __func__);
+       return 0;
+
+fail_csi_cfg:
+       dev->platform_data->csi_cfg(sd, 0);
+fail_power_on:
+       power_down(sd);
+       dev_err(&client->dev, "sensor power-gating failed\n");
+fail_power_off:
+       if (dev->platform_data->platform_deinit)
+               dev->platform_data->platform_deinit();
+platform_init_failed:
+       mutex_unlock(&dev->input_lock);
+       return ret;
+}
+
+static int gc0310_g_parm(struct v4l2_subdev *sd,
+                       struct v4l2_streamparm *param)
+{
+       struct gc0310_device *dev = to_gc0310_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (!param)
+               return -EINVAL;
+
+       if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               dev_err(&client->dev,  "unsupported buffer type.\n");
+               return -EINVAL;
+       }
+
+       memset(param, 0, sizeof(*param));
+       param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+       if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) {
+               param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+               param->parm.capture.timeperframe.numerator = 1;
+               param->parm.capture.capturemode = dev->run_mode;
+               param->parm.capture.timeperframe.denominator =
+                       gc0310_res[dev->fmt_idx].fps;
+       }
+       return 0;
+}
+
+static int gc0310_s_parm(struct v4l2_subdev *sd,
+                       struct v4l2_streamparm *param)
+{
+       struct gc0310_device *dev = to_gc0310_sensor(sd);
+       dev->run_mode = param->parm.capture.capturemode;
+
+       mutex_lock(&dev->input_lock);
+       switch (dev->run_mode) {
+       case CI_MODE_VIDEO:
+               gc0310_res = gc0310_res_video;
+               N_RES = N_RES_VIDEO;
+               break;
+       case CI_MODE_STILL_CAPTURE:
+               gc0310_res = gc0310_res_still;
+               N_RES = N_RES_STILL;
+               break;
+       default:
+               gc0310_res = gc0310_res_preview;
+               N_RES = N_RES_PREVIEW;
+       }
+       mutex_unlock(&dev->input_lock);
+       return 0;
+}
+
+static int gc0310_g_frame_interval(struct v4l2_subdev *sd,
+                                  struct v4l2_subdev_frame_interval *interval)
+{
+       struct gc0310_device *dev = to_gc0310_sensor(sd);
+
+       interval->interval.numerator = 1;
+       interval->interval.denominator = gc0310_res[dev->fmt_idx].fps;
+
+       return 0;
+}
+
+static int gc0310_enum_mbus_code(struct v4l2_subdev *sd,
+                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_mbus_code_enum *code)
+{
+       if (code->index >= MAX_FMTS)
+               return -EINVAL;
+
+       code->code = MEDIA_BUS_FMT_SGRBG8_1X8;
+       return 0;
+}
+
+static int gc0310_enum_frame_size(struct v4l2_subdev *sd,
+                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_frame_size_enum *fse)
+{
+       int index = fse->index;
+
+       if (index >= N_RES)
+               return -EINVAL;
+
+       fse->min_width = gc0310_res[index].width;
+       fse->min_height = gc0310_res[index].height;
+       fse->max_width = gc0310_res[index].width;
+       fse->max_height = gc0310_res[index].height;
+
+       return 0;
+
+}
+
+
+static int gc0310_g_skip_frames(struct v4l2_subdev *sd, u32 *frames)
+{
+       struct gc0310_device *dev = to_gc0310_sensor(sd);
+
+       mutex_lock(&dev->input_lock);
+       *frames = gc0310_res[dev->fmt_idx].skip_frames;
+       mutex_unlock(&dev->input_lock);
+
+       return 0;
+}
+
+static const struct v4l2_subdev_sensor_ops gc0310_sensor_ops = {
+       .g_skip_frames  = gc0310_g_skip_frames,
+};
+
+static const struct v4l2_subdev_video_ops gc0310_video_ops = {
+       .s_stream = gc0310_s_stream,
+       .g_parm = gc0310_g_parm,
+       .s_parm = gc0310_s_parm,
+       .g_frame_interval = gc0310_g_frame_interval,
+};
+
+static const struct v4l2_subdev_core_ops gc0310_core_ops = {
+       .s_power = gc0310_s_power,
+       .ioctl = gc0310_ioctl,
+};
+
+static const struct v4l2_subdev_pad_ops gc0310_pad_ops = {
+       .enum_mbus_code = gc0310_enum_mbus_code,
+       .enum_frame_size = gc0310_enum_frame_size,
+       .get_fmt = gc0310_get_fmt,
+       .set_fmt = gc0310_set_fmt,
+};
+
+static const struct v4l2_subdev_ops gc0310_ops = {
+       .core = &gc0310_core_ops,
+       .video = &gc0310_video_ops,
+       .pad = &gc0310_pad_ops,
+       .sensor = &gc0310_sensor_ops,
+};
+
+static int gc0310_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct gc0310_device *dev = to_gc0310_sensor(sd);
+       dev_dbg(&client->dev, "gc0310_remove...\n");
+
+       if (dev->platform_data->platform_deinit)
+               dev->platform_data->platform_deinit();
+
+       dev->platform_data->csi_cfg(sd, 0);
+
+       v4l2_device_unregister_subdev(sd);
+       media_entity_cleanup(&dev->sd.entity);
+       v4l2_ctrl_handler_free(&dev->ctrl_handler);
+       kfree(dev);
+
+       return 0;
+}
+
+static int gc0310_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct gc0310_device *dev;
+       int ret;
+       void *pdata;
+       unsigned int i;
+
+       pr_info("%s S\n", __func__);
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev) {
+               dev_err(&client->dev, "out of memory\n");
+               return -ENOMEM;
+       }
+
+       mutex_init(&dev->input_lock);
+
+       dev->fmt_idx = 0;
+       v4l2_i2c_subdev_init(&(dev->sd), client, &gc0310_ops);
+
+       if (ACPI_COMPANION(&client->dev))
+               pdata = gmin_camera_platform_data(&dev->sd,
+                                                 ATOMISP_INPUT_FORMAT_RAW_8,
+                                                 atomisp_bayer_order_grbg);
+       else
+               pdata = client->dev.platform_data;
+
+       if (!pdata) {
+               ret = -EINVAL;
+               goto out_free;
+       }
+
+       ret = gc0310_s_config(&dev->sd, client->irq, pdata);
+       if (ret)
+               goto out_free;
+
+       ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA);
+       if (ret)
+               goto out_free;
+
+       dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+       dev->pad.flags = MEDIA_PAD_FL_SOURCE;
+       dev->format.code = MEDIA_BUS_FMT_SGRBG8_1X8;
+       dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+       ret =
+           v4l2_ctrl_handler_init(&dev->ctrl_handler,
+                                  ARRAY_SIZE(gc0310_controls));
+       if (ret) {
+               gc0310_remove(client);
+               return ret;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(gc0310_controls); i++)
+               v4l2_ctrl_new_custom(&dev->ctrl_handler, &gc0310_controls[i],
+                                    NULL);
+
+       if (dev->ctrl_handler.error) {
+               gc0310_remove(client);
+               return dev->ctrl_handler.error;
+       }
+
+       /* Use same lock for controls as for everything else. */
+       dev->ctrl_handler.lock = &dev->input_lock;
+       dev->sd.ctrl_handler = &dev->ctrl_handler;
+
+       ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad);
+       if (ret)
+               gc0310_remove(client);
+
+       pr_info("%s E\n", __func__);
+       return ret;
+out_free:
+       v4l2_device_unregister_subdev(&dev->sd);
+       kfree(dev);
+       return ret;
+}
+
+static const struct acpi_device_id gc0310_acpi_match[] = {
+       {"XXGC0310"},
+       {"INT0310"},
+       {},
+};
+
+MODULE_DEVICE_TABLE(acpi, gc0310_acpi_match);
+
+MODULE_DEVICE_TABLE(i2c, gc0310_id);
+static struct i2c_driver gc0310_driver = {
+       .driver = {
+               .name = GC0310_NAME,
+               .acpi_match_table = ACPI_PTR(gc0310_acpi_match),
+       },
+       .probe = gc0310_probe,
+       .remove = gc0310_remove,
+       .id_table = gc0310_id,
+};
+
+static int init_gc0310(void)
+{
+       return i2c_add_driver(&gc0310_driver);
+}
+
+static void exit_gc0310(void)
+{
+
+       i2c_del_driver(&gc0310_driver);
+}
+
+module_init(init_gc0310);
+module_exit(exit_gc0310);
+
+MODULE_AUTHOR("Lai, Angie <angie.lai@intel.com>");
+MODULE_DESCRIPTION("A low-level driver for GalaxyCore GC0310 sensors");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c
new file mode 100644 (file)
index 0000000..e43d31e
--- /dev/null
@@ -0,0 +1,1219 @@
+/*
+ * Support for GalaxyCore GC2235 2M camera sensor.
+ *
+ * Copyright (c) 2014 Intel Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kmod.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/moduleparam.h>
+#include <media/v4l2-device.h>
+#include "../include/linux/atomisp_gmin_platform.h"
+#include <linux/acpi.h>
+#include <linux/io.h>
+
+#include "gc2235.h"
+
+/* i2c read/write stuff */
+static int gc2235_read_reg(struct i2c_client *client,
+                          u16 data_length, u16 reg, u16 *val)
+{
+       int err;
+       struct i2c_msg msg[2];
+       unsigned char data[6];
+
+       if (!client->adapter) {
+               dev_err(&client->dev, "%s error, no client->adapter\n",
+                       __func__);
+               return -ENODEV;
+       }
+
+       if (data_length != GC2235_8BIT) {
+               dev_err(&client->dev, "%s error, invalid data length\n",
+                       __func__);
+               return -EINVAL;
+       }
+
+       memset(msg, 0, sizeof(msg));
+
+       msg[0].addr = client->addr;
+       msg[0].flags = 0;
+       msg[0].len = 1;
+       msg[0].buf = data;
+
+       /* high byte goes out first */
+       data[0] = (u8)(reg & 0xff);
+
+       msg[1].addr = client->addr;
+       msg[1].len = data_length;
+       msg[1].flags = I2C_M_RD;
+       msg[1].buf = data;
+
+       err = i2c_transfer(client->adapter, msg, 2);
+       if (err != 2) {
+               if (err >= 0)
+                       err = -EIO;
+               dev_err(&client->dev,
+                       "read from offset 0x%x error %d", reg, err);
+               return err;
+       }
+
+       *val = 0;
+       /* high byte comes first */
+       if (data_length == GC2235_8BIT)
+               *val = (u8)data[0];
+
+       return 0;
+}
+
+static int gc2235_i2c_write(struct i2c_client *client, u16 len, u8 *data)
+{
+       struct i2c_msg msg;
+       const int num_msg = 1;
+       int ret;
+
+       msg.addr = client->addr;
+       msg.flags = 0;
+       msg.len = len;
+       msg.buf = data;
+       ret = i2c_transfer(client->adapter, &msg, 1);
+
+       return ret == num_msg ? 0 : -EIO;
+}
+
+static int gc2235_write_reg(struct i2c_client *client, u16 data_length,
+                                                       u8 reg, u8 val)
+{
+       int ret;
+       unsigned char data[4] = {0};
+       const u16 len = data_length + sizeof(u8); /* 16-bit address + data */
+
+       if (data_length != GC2235_8BIT) {
+               dev_err(&client->dev,
+                       "%s error, invalid data_length\n", __func__);
+               return -EINVAL;
+       }
+
+       /* high byte goes out first */
+       data[0] = reg;
+       data[1] = val;
+
+       ret = gc2235_i2c_write(client, len, data);
+       if (ret)
+               dev_err(&client->dev,
+                       "write error: wrote 0x%x to offset 0x%x error %d",
+                       val, reg, ret);
+
+       return ret;
+}
+
+static int __gc2235_flush_reg_array(struct i2c_client *client,
+                                   struct gc2235_write_ctrl *ctrl)
+{
+       u16 size;
+
+       if (ctrl->index == 0)
+               return 0;
+
+       size = sizeof(u8) + ctrl->index; /* 8-bit address + data */
+       ctrl->index = 0;
+
+       return gc2235_i2c_write(client, size, (u8 *)&ctrl->buffer);
+}
+
+static int __gc2235_buf_reg_array(struct i2c_client *client,
+                                 struct gc2235_write_ctrl *ctrl,
+                                 const struct gc2235_reg *next)
+{
+       int size;
+
+       if (next->type != GC2235_8BIT)
+               return -EINVAL;
+
+       size = 1;
+       ctrl->buffer.data[ctrl->index] = (u8)next->val;
+
+       /* When first item is added, we need to store its starting address */
+       if (ctrl->index == 0)
+               ctrl->buffer.addr = next->reg;
+
+       ctrl->index += size;
+
+       /*
+        * Buffer cannot guarantee free space for u32? Better flush it to avoid
+        * possible lack of memory for next item.
+        */
+       if (ctrl->index + sizeof(u8) >= GC2235_MAX_WRITE_BUF_SIZE)
+               return __gc2235_flush_reg_array(client, ctrl);
+
+       return 0;
+}
+static int __gc2235_write_reg_is_consecutive(struct i2c_client *client,
+                                            struct gc2235_write_ctrl *ctrl,
+                                            const struct gc2235_reg *next)
+{
+       if (ctrl->index == 0)
+               return 1;
+
+       return ctrl->buffer.addr + ctrl->index == next->reg;
+}
+static int gc2235_write_reg_array(struct i2c_client *client,
+                                 const struct gc2235_reg *reglist)
+{
+       const struct gc2235_reg *next = reglist;
+       struct gc2235_write_ctrl ctrl;
+       int err;
+
+       ctrl.index = 0;
+       for (; next->type != GC2235_TOK_TERM; next++) {
+               switch (next->type & GC2235_TOK_MASK) {
+               case GC2235_TOK_DELAY:
+                       err = __gc2235_flush_reg_array(client, &ctrl);
+                       if (err)
+                               return err;
+                       msleep(next->val);
+                       break;
+               default:
+                       /*
+                        * If next address is not consecutive, data needs to be
+                        * flushed before proceed.
+                        */
+                       if (!__gc2235_write_reg_is_consecutive(client, &ctrl,
+                                                               next)) {
+                               err = __gc2235_flush_reg_array(client, &ctrl);
+                               if (err)
+                                       return err;
+                       }
+                       err = __gc2235_buf_reg_array(client, &ctrl, next);
+                       if (err) {
+                               dev_err(&client->dev, "%s: write error, aborted\n",
+                                        __func__);
+                               return err;
+                       }
+                       break;
+               }
+       }
+
+       return __gc2235_flush_reg_array(client, &ctrl);
+}
+
+static int gc2235_g_focal(struct v4l2_subdev *sd, s32 *val)
+{
+       *val = (GC2235_FOCAL_LENGTH_NUM << 16) | GC2235_FOCAL_LENGTH_DEM;
+       return 0;
+}
+
+static int gc2235_g_fnumber(struct v4l2_subdev *sd, s32 *val)
+{
+       /*const f number for imx*/
+       *val = (GC2235_F_NUMBER_DEFAULT_NUM << 16) | GC2235_F_NUMBER_DEM;
+       return 0;
+}
+
+static int gc2235_g_fnumber_range(struct v4l2_subdev *sd, s32 *val)
+{
+       *val = (GC2235_F_NUMBER_DEFAULT_NUM << 24) |
+               (GC2235_F_NUMBER_DEM << 16) |
+               (GC2235_F_NUMBER_DEFAULT_NUM << 8) | GC2235_F_NUMBER_DEM;
+       return 0;
+}
+
+
+static int gc2235_get_intg_factor(struct i2c_client *client,
+                               struct camera_mipi_info *info,
+                               const struct gc2235_resolution *res)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct gc2235_device *dev = to_gc2235_sensor(sd);
+       struct atomisp_sensor_mode_data *buf = &info->data;
+       u16 reg_val, reg_val_h, dummy;
+       int ret;
+
+       if (!info)
+               return -EINVAL;
+
+       /* pixel clock calculattion */
+       buf->vt_pix_clk_freq_mhz = dev->vt_pix_clk_freq_mhz = 30000000;
+
+       /* get integration time */
+       buf->coarse_integration_time_min = GC2235_COARSE_INTG_TIME_MIN;
+       buf->coarse_integration_time_max_margin =
+                                       GC2235_COARSE_INTG_TIME_MAX_MARGIN;
+
+       buf->fine_integration_time_min = GC2235_FINE_INTG_TIME_MIN;
+       buf->fine_integration_time_max_margin =
+                                       GC2235_FINE_INTG_TIME_MAX_MARGIN;
+
+       buf->fine_integration_time_def = GC2235_FINE_INTG_TIME_MIN;
+       buf->frame_length_lines = res->lines_per_frame;
+       buf->line_length_pck = res->pixels_per_line;
+       buf->read_mode = res->bin_mode;
+
+       /* get the cropping and output resolution to ISP for this mode. */
+       ret =  gc2235_read_reg(client, GC2235_8BIT,
+                                       GC2235_H_CROP_START_H, &reg_val_h);
+       ret =  gc2235_read_reg(client, GC2235_8BIT,
+                                       GC2235_H_CROP_START_L, &reg_val);
+       if (ret)
+               return ret;
+
+       buf->crop_horizontal_start = (reg_val_h << 8) | reg_val;
+
+       ret =  gc2235_read_reg(client, GC2235_8BIT,
+                                       GC2235_V_CROP_START_H, &reg_val_h);
+       ret =  gc2235_read_reg(client, GC2235_8BIT,
+                                       GC2235_V_CROP_START_L, &reg_val);
+       if (ret)
+               return ret;
+
+       buf->crop_vertical_start = (reg_val_h << 8) | reg_val;
+
+       ret = gc2235_read_reg(client, GC2235_8BIT,
+                                       GC2235_H_OUTSIZE_H, &reg_val_h);
+       ret = gc2235_read_reg(client, GC2235_8BIT,
+                                       GC2235_H_OUTSIZE_L, &reg_val);
+       if (ret)
+               return ret;
+       buf->output_width = (reg_val_h << 8) | reg_val;
+
+       ret = gc2235_read_reg(client, GC2235_8BIT,
+                                       GC2235_V_OUTSIZE_H, &reg_val_h);
+       ret = gc2235_read_reg(client, GC2235_8BIT,
+                                       GC2235_V_OUTSIZE_L, &reg_val);
+       if (ret)
+               return ret;
+       buf->output_height = (reg_val_h << 8) | reg_val;
+
+       buf->crop_horizontal_end = buf->crop_horizontal_start +
+                                               buf->output_width - 1;
+       buf->crop_vertical_end = buf->crop_vertical_start +
+                                               buf->output_height - 1;
+
+       ret = gc2235_read_reg(client, GC2235_8BIT,
+                                       GC2235_HB_H, &reg_val_h);
+       ret = gc2235_read_reg(client, GC2235_8BIT,
+                                       GC2235_HB_L, &reg_val);
+       if (ret)
+               return ret;
+
+       dummy = (reg_val_h << 8) | reg_val;
+
+       ret = gc2235_read_reg(client, GC2235_8BIT,
+                                       GC2235_SH_DELAY_H, &reg_val_h);
+       ret = gc2235_read_reg(client, GC2235_8BIT,
+                                       GC2235_SH_DELAY_L, &reg_val);
+
+#if 0
+       buf->line_length_pck = buf->output_width + 16 + dummy +
+                               (((u16)reg_val_h << 8) | (u16)reg_val) + 4;
+#endif
+       ret = gc2235_read_reg(client, GC2235_8BIT,
+                                       GC2235_VB_H, &reg_val_h);
+       ret = gc2235_read_reg(client, GC2235_8BIT,
+                                       GC2235_VB_L, &reg_val);
+       if (ret)
+               return ret;
+
+#if 0
+       buf->frame_length_lines = buf->output_height + 32 +
+                               (((u16)reg_val_h << 8) | (u16)reg_val);
+#endif
+       buf->binning_factor_x = res->bin_factor_x ?
+                                       res->bin_factor_x : 1;
+       buf->binning_factor_y = res->bin_factor_y ?
+                                       res->bin_factor_y : 1;
+       return 0;
+}
+
+static long __gc2235_set_exposure(struct v4l2_subdev *sd, int coarse_itg,
+                                int gain, int digitgain)
+
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       u16 coarse_integration = (u16)coarse_itg;
+       int ret = 0;
+       u16 expo_coarse_h, expo_coarse_l, gain_val = 0xF0, gain_val2 = 0xF0;
+       expo_coarse_h = coarse_integration >> 8;
+       expo_coarse_l = coarse_integration & 0xff;
+
+       ret = gc2235_write_reg(client, GC2235_8BIT,
+                                       GC2235_EXPOSURE_H, expo_coarse_h);
+       ret = gc2235_write_reg(client, GC2235_8BIT,
+                                       GC2235_EXPOSURE_L, expo_coarse_l);
+
+       if (gain <= 0x58) {
+               gain_val = 0x40;
+               gain_val2 = 0x58;
+       } else if (gain < 256) {
+               gain_val = 0x40;
+               gain_val2 = gain;
+       } else {
+               gain_val2 = 64 * gain / 256;
+               gain_val = 0xff;
+       }
+
+       ret = gc2235_write_reg(client, GC2235_8BIT,
+                                       GC2235_GLOBAL_GAIN, (u8)gain_val);
+       ret = gc2235_write_reg(client, GC2235_8BIT,
+                                       GC2235_PRE_GAIN, (u8)gain_val2);
+
+       return ret;
+}
+
+
+static int gc2235_set_exposure(struct v4l2_subdev *sd, int exposure,
+       int gain, int digitgain)
+{
+       struct gc2235_device *dev = to_gc2235_sensor(sd);
+       int ret;
+
+       mutex_lock(&dev->input_lock);
+       ret = __gc2235_set_exposure(sd, exposure, gain, digitgain);
+       mutex_unlock(&dev->input_lock);
+
+       return ret;
+}
+
+static long gc2235_s_exposure(struct v4l2_subdev *sd,
+                              struct atomisp_exposure *exposure)
+{
+       int exp = exposure->integration_time[0];
+       int gain = exposure->gain[0];
+       int digitgain = exposure->gain[1];
+
+       /* we should not accept the invalid value below. */
+       if (gain == 0) {
+               struct i2c_client *client = v4l2_get_subdevdata(sd);
+               v4l2_err(client, "%s: invalid value\n", __func__);
+               return -EINVAL;
+       }
+
+       return gc2235_set_exposure(sd, exp, gain, digitgain);
+}
+static long gc2235_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+       switch (cmd) {
+       case ATOMISP_IOC_S_EXPOSURE:
+               return gc2235_s_exposure(sd, arg);
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+/* This returns the exposure time being used. This should only be used
+ * for filling in EXIF data, not for actual image processing.
+ */
+static int gc2235_q_exposure(struct v4l2_subdev *sd, s32 *value)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       u16 reg_v, reg_v2;
+       int ret;
+
+       /* get exposure */
+       ret = gc2235_read_reg(client, GC2235_8BIT,
+                                       GC2235_EXPOSURE_L,
+                                       &reg_v);
+       if (ret)
+               goto err;
+
+       ret = gc2235_read_reg(client, GC2235_8BIT,
+                                       GC2235_EXPOSURE_H,
+                                       &reg_v2);
+       if (ret)
+               goto err;
+
+       reg_v += reg_v2 << 8;
+
+       *value = reg_v;
+err:
+       return ret;
+}
+
+static int gc2235_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct gc2235_device *dev =
+           container_of(ctrl->handler, struct gc2235_device, ctrl_handler);
+       int ret = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE_ABSOLUTE:
+               ret = gc2235_q_exposure(&dev->sd, &ctrl->val);
+               break;
+       case V4L2_CID_FOCAL_ABSOLUTE:
+               ret = gc2235_g_focal(&dev->sd, &ctrl->val);
+               break;
+       case V4L2_CID_FNUMBER_ABSOLUTE:
+               ret = gc2235_g_fnumber(&dev->sd, &ctrl->val);
+               break;
+       case V4L2_CID_FNUMBER_RANGE:
+               ret = gc2235_g_fnumber_range(&dev->sd, &ctrl->val);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static const struct v4l2_ctrl_ops ctrl_ops = {
+       .g_volatile_ctrl = gc2235_g_volatile_ctrl
+};
+
+static struct v4l2_ctrl_config gc2235_controls[] = {
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_EXPOSURE_ABSOLUTE,
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .name = "exposure",
+        .min = 0x0,
+        .max = 0xffff,
+        .step = 0x01,
+        .def = 0x00,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_FOCAL_ABSOLUTE,
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .name = "focal length",
+        .min = GC2235_FOCAL_LENGTH_DEFAULT,
+        .max = GC2235_FOCAL_LENGTH_DEFAULT,
+        .step = 0x01,
+        .def = GC2235_FOCAL_LENGTH_DEFAULT,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_FNUMBER_ABSOLUTE,
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .name = "f-number",
+        .min = GC2235_F_NUMBER_DEFAULT,
+        .max = GC2235_F_NUMBER_DEFAULT,
+        .step = 0x01,
+        .def = GC2235_F_NUMBER_DEFAULT,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_FNUMBER_RANGE,
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .name = "f-number range",
+        .min = GC2235_F_NUMBER_RANGE,
+        .max = GC2235_F_NUMBER_RANGE,
+        .step = 0x01,
+        .def = GC2235_F_NUMBER_RANGE,
+        .flags = 0,
+        },
+};
+
+static int __gc2235_init(struct v4l2_subdev *sd)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       /* restore settings */
+       gc2235_res = gc2235_res_preview;
+       N_RES = N_RES_PREVIEW;
+
+       return gc2235_write_reg_array(client, gc2235_init_settings);
+}
+
+static int is_init;
+
+static int power_ctrl(struct v4l2_subdev *sd, bool flag)
+{
+       int ret = -1;
+       struct gc2235_device *dev = to_gc2235_sensor(sd);
+
+       if (!dev || !dev->platform_data)
+               return -ENODEV;
+
+       /* Non-gmin platforms use the legacy callback */
+       if (dev->platform_data->power_ctrl)
+               return dev->platform_data->power_ctrl(sd, flag);
+
+       if (flag) {
+               ret = dev->platform_data->v1p8_ctrl(sd, 1);
+               usleep_range(60, 90);
+               if (ret == 0)
+                       ret |= dev->platform_data->v2p8_ctrl(sd, 1);
+       } else {
+               ret = dev->platform_data->v1p8_ctrl(sd, 0);
+               ret |= dev->platform_data->v2p8_ctrl(sd, 0);
+       }
+       return ret;
+}
+
+static int gpio_ctrl(struct v4l2_subdev *sd, bool flag)
+{
+       struct gc2235_device *dev = to_gc2235_sensor(sd);
+       int ret = -1;
+
+       if (!dev || !dev->platform_data)
+               return -ENODEV;
+
+       /* Non-gmin platforms use the legacy callback */
+       if (dev->platform_data->gpio_ctrl)
+               return dev->platform_data->gpio_ctrl(sd, flag);
+
+       ret |= dev->platform_data->gpio1_ctrl(sd, !flag);
+       usleep_range(60, 90);
+       return dev->platform_data->gpio0_ctrl(sd, flag);
+}
+
+static int power_up(struct v4l2_subdev *sd)
+{
+       struct gc2235_device *dev = to_gc2235_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret;
+
+       if (!dev->platform_data) {
+               dev_err(&client->dev,
+                       "no camera_sensor_platform_data");
+               return -ENODEV;
+       }
+       /* power control */
+       ret = power_ctrl(sd, 1);
+       if (ret)
+               goto fail_power;
+
+       /* according to DS, at least 5ms is needed between DOVDD and PWDN */
+       usleep_range(5000, 6000);
+
+       ret = dev->platform_data->flisclk_ctrl(sd, 1);
+       if (ret)
+               goto fail_clk;
+       usleep_range(5000, 6000);
+
+       /* gpio ctrl */
+       ret = gpio_ctrl(sd, 1);
+       if (ret) {
+               ret = gpio_ctrl(sd, 1);
+               if (ret)
+                       goto fail_power;
+       }
+
+       msleep(5);
+       return 0;
+
+fail_clk:
+       gpio_ctrl(sd, 0);
+fail_power:
+       power_ctrl(sd, 0);
+       dev_err(&client->dev, "sensor power-up failed\n");
+
+       return ret;
+}
+
+static int power_down(struct v4l2_subdev *sd)
+{
+       struct gc2235_device *dev = to_gc2235_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret = 0;
+
+       if (!dev->platform_data) {
+               dev_err(&client->dev,
+                       "no camera_sensor_platform_data");
+               return -ENODEV;
+       }
+       /* gpio ctrl */
+       ret = gpio_ctrl(sd, 0);
+       if (ret) {
+               ret = gpio_ctrl(sd, 0);
+               if (ret)
+                       dev_err(&client->dev, "gpio failed 2\n");
+       }
+
+       ret = dev->platform_data->flisclk_ctrl(sd, 0);
+       if (ret)
+               dev_err(&client->dev, "flisclk failed\n");
+
+       /* power control */
+       ret = power_ctrl(sd, 0);
+       if (ret)
+               dev_err(&client->dev, "vprog failed.\n");
+
+       return ret;
+}
+
+static int gc2235_s_power(struct v4l2_subdev *sd, int on)
+{
+       int ret;
+
+       if (on == 0)
+               ret = power_down(sd);
+       else {
+               ret = power_up(sd);
+               if (!ret)
+                       ret = __gc2235_init(sd);
+               is_init = 1;
+       }
+       return ret;
+}
+
+/*
+ * distance - calculate the distance
+ * @res: resolution
+ * @w: width
+ * @h: height
+ *
+ * Get the gap between resolution and w/h.
+ * res->width/height smaller than w/h wouldn't be considered.
+ * Returns the value of gap or -1 if fail.
+ */
+#define LARGEST_ALLOWED_RATIO_MISMATCH 800
+static int distance(struct gc2235_resolution *res, u32 w, u32 h)
+{
+       unsigned int w_ratio = (res->width << 13) / w;
+       unsigned int h_ratio;
+       int match;
+
+       if (h == 0)
+               return -1;
+       h_ratio = (res->height << 13) / h;
+       if (h_ratio == 0)
+               return -1;
+       match   = abs(((w_ratio << 13) / h_ratio) - 8192);
+
+       if ((w_ratio < 8192) || (h_ratio < 8192) ||
+           (match > LARGEST_ALLOWED_RATIO_MISMATCH))
+               return -1;
+
+       return w_ratio + h_ratio;
+}
+
+/* Return the nearest higher resolution index */
+static int nearest_resolution_index(int w, int h)
+{
+       int i;
+       int idx = -1;
+       int dist;
+       int min_dist = INT_MAX;
+       struct gc2235_resolution *tmp_res = NULL;
+
+       for (i = 0; i < N_RES; i++) {
+               tmp_res = &gc2235_res[i];
+               dist = distance(tmp_res, w, h);
+               if (dist == -1)
+                       continue;
+               if (dist < min_dist) {
+                       min_dist = dist;
+                       idx = i;
+               }
+       }
+
+       return idx;
+}
+
+static int get_resolution_index(int w, int h)
+{
+       int i;
+
+       for (i = 0; i < N_RES; i++) {
+               if (w != gc2235_res[i].width)
+                       continue;
+               if (h != gc2235_res[i].height)
+                       continue;
+
+               return i;
+       }
+
+       return -1;
+}
+
+static int startup(struct v4l2_subdev *sd)
+{
+       struct gc2235_device *dev = to_gc2235_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret = 0;
+       if (is_init == 0) {
+               /* force gc2235 to do a reset in res change, otherwise it
+               * can not output normal after switching res. and it is not
+               * necessary for first time run up after power on, for the sack
+               * of performance
+               */
+               power_down(sd);
+               power_up(sd);
+               gc2235_write_reg_array(client, gc2235_init_settings);
+       }
+
+       ret = gc2235_write_reg_array(client, gc2235_res[dev->fmt_idx].regs);
+       if (ret) {
+               dev_err(&client->dev, "gc2235 write register err.\n");
+               return ret;
+       }
+       is_init = 0;
+
+       return ret;
+}
+
+static int gc2235_set_fmt(struct v4l2_subdev *sd,
+                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_format *format)
+{
+
+       struct v4l2_mbus_framefmt *fmt = &format->format;
+       struct gc2235_device *dev = to_gc2235_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct camera_mipi_info *gc2235_info = NULL;
+       int ret = 0;
+       int idx;
+
+       gc2235_info = v4l2_get_subdev_hostdata(sd);
+       if (!gc2235_info)
+               return -EINVAL;
+       if (format->pad)
+               return -EINVAL;
+       if (!fmt)
+               return -EINVAL;
+       mutex_lock(&dev->input_lock);
+       idx = nearest_resolution_index(fmt->width, fmt->height);
+       if (idx == -1) {
+               /* return the largest resolution */
+               fmt->width = gc2235_res[N_RES - 1].width;
+               fmt->height = gc2235_res[N_RES - 1].height;
+       } else {
+               fmt->width = gc2235_res[idx].width;
+               fmt->height = gc2235_res[idx].height;
+       }
+       fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
+       if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+               cfg->try_fmt = *fmt;
+               mutex_unlock(&dev->input_lock);
+               return 0;
+       }
+
+       dev->fmt_idx = get_resolution_index(fmt->width, fmt->height);
+       if (dev->fmt_idx == -1) {
+               dev_err(&client->dev, "get resolution fail\n");
+               mutex_unlock(&dev->input_lock);
+               return -EINVAL;
+       }
+
+       ret = startup(sd);
+       if (ret) {
+               dev_err(&client->dev, "gc2235 startup err\n");
+               goto err;
+       }
+
+       ret = gc2235_get_intg_factor(client, gc2235_info,
+                                    &gc2235_res[dev->fmt_idx]);
+       if (ret)
+               dev_err(&client->dev, "failed to get integration_factor\n");
+
+err:
+       mutex_unlock(&dev->input_lock);
+       return ret;
+}
+
+static int gc2235_get_fmt(struct v4l2_subdev *sd,
+                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_format *format)
+{
+       struct v4l2_mbus_framefmt *fmt = &format->format;
+       struct gc2235_device *dev = to_gc2235_sensor(sd);
+
+       if (format->pad)
+               return -EINVAL;
+
+       if (!fmt)
+               return -EINVAL;
+
+       fmt->width = gc2235_res[dev->fmt_idx].width;
+       fmt->height = gc2235_res[dev->fmt_idx].height;
+       fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
+
+       return 0;
+}
+
+static int gc2235_detect(struct i2c_client *client)
+{
+       struct i2c_adapter *adapter = client->adapter;
+       u16 high, low;
+       int ret;
+       u16 id;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
+               return -ENODEV;
+
+       ret = gc2235_read_reg(client, GC2235_8BIT,
+                                       GC2235_SENSOR_ID_H, &high);
+       if (ret) {
+               dev_err(&client->dev, "sensor_id_high = 0x%x\n", high);
+               return -ENODEV;
+       }
+       ret = gc2235_read_reg(client, GC2235_8BIT,
+                                       GC2235_SENSOR_ID_L, &low);
+       id = ((high << 8) | low);
+
+       if (id != GC2235_ID) {
+               dev_err(&client->dev, "sensor ID error, 0x%x\n", id);
+               return -ENODEV;
+       }
+
+       dev_info(&client->dev, "detect gc2235 success\n");
+       return 0;
+}
+
+static int gc2235_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct gc2235_device *dev = to_gc2235_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret;
+       mutex_lock(&dev->input_lock);
+
+       if (enable)
+               ret = gc2235_write_reg_array(client, gc2235_stream_on);
+       else
+               ret = gc2235_write_reg_array(client, gc2235_stream_off);
+
+       mutex_unlock(&dev->input_lock);
+       return ret;
+}
+
+
+static int gc2235_s_config(struct v4l2_subdev *sd,
+                          int irq, void *platform_data)
+{
+       struct gc2235_device *dev = to_gc2235_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret = 0;
+
+       if (!platform_data)
+               return -ENODEV;
+
+       dev->platform_data =
+               (struct camera_sensor_platform_data *)platform_data;
+
+       mutex_lock(&dev->input_lock);
+       if (dev->platform_data->platform_init) {
+               ret = dev->platform_data->platform_init(client);
+               if (ret) {
+                       dev_err(&client->dev, "platform init err\n");
+                       goto platform_init_failed;
+               }
+       }
+       /* power off the module, then power on it in future
+        * as first power on by board may not fulfill the
+        * power on sequqence needed by the module
+        */
+       ret = power_down(sd);
+       if (ret) {
+               dev_err(&client->dev, "gc2235 power-off err.\n");
+               goto fail_power_off;
+       }
+
+       ret = power_up(sd);
+       if (ret) {
+               dev_err(&client->dev, "gc2235 power-up err.\n");
+               goto fail_power_on;
+       }
+
+       ret = dev->platform_data->csi_cfg(sd, 1);
+       if (ret)
+               goto fail_csi_cfg;
+
+       /* config & detect sensor */
+       ret = gc2235_detect(client);
+       if (ret) {
+               dev_err(&client->dev, "gc2235_detect err s_config.\n");
+               goto fail_csi_cfg;
+       }
+
+       /* turn off sensor, after probed */
+       ret = power_down(sd);
+       if (ret) {
+               dev_err(&client->dev, "gc2235 power-off err.\n");
+               goto fail_csi_cfg;
+       }
+       mutex_unlock(&dev->input_lock);
+
+       return 0;
+
+fail_csi_cfg:
+       dev->platform_data->csi_cfg(sd, 0);
+fail_power_on:
+       power_down(sd);
+       dev_err(&client->dev, "sensor power-gating failed\n");
+fail_power_off:
+       if (dev->platform_data->platform_deinit)
+               dev->platform_data->platform_deinit();
+platform_init_failed:
+       mutex_unlock(&dev->input_lock);
+       return ret;
+}
+
+static int gc2235_g_parm(struct v4l2_subdev *sd,
+                       struct v4l2_streamparm *param)
+{
+       struct gc2235_device *dev = to_gc2235_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (!param)
+               return -EINVAL;
+
+       if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               dev_err(&client->dev,  "unsupported buffer type.\n");
+               return -EINVAL;
+       }
+
+       memset(param, 0, sizeof(*param));
+       param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+       if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) {
+               param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+               param->parm.capture.timeperframe.numerator = 1;
+               param->parm.capture.capturemode = dev->run_mode;
+               param->parm.capture.timeperframe.denominator =
+                       gc2235_res[dev->fmt_idx].fps;
+       }
+       return 0;
+}
+
+static int gc2235_s_parm(struct v4l2_subdev *sd,
+                       struct v4l2_streamparm *param)
+{
+       struct gc2235_device *dev = to_gc2235_sensor(sd);
+       dev->run_mode = param->parm.capture.capturemode;
+
+       mutex_lock(&dev->input_lock);
+       switch (dev->run_mode) {
+       case CI_MODE_VIDEO:
+               gc2235_res = gc2235_res_video;
+               N_RES = N_RES_VIDEO;
+               break;
+       case CI_MODE_STILL_CAPTURE:
+               gc2235_res = gc2235_res_still;
+               N_RES = N_RES_STILL;
+               break;
+       default:
+               gc2235_res = gc2235_res_preview;
+               N_RES = N_RES_PREVIEW;
+       }
+       mutex_unlock(&dev->input_lock);
+       return 0;
+}
+
+static int gc2235_g_frame_interval(struct v4l2_subdev *sd,
+                                  struct v4l2_subdev_frame_interval *interval)
+{
+       struct gc2235_device *dev = to_gc2235_sensor(sd);
+
+       interval->interval.numerator = 1;
+       interval->interval.denominator = gc2235_res[dev->fmt_idx].fps;
+
+       return 0;
+}
+
+static int gc2235_enum_mbus_code(struct v4l2_subdev *sd,
+                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_mbus_code_enum *code)
+{
+       if (code->index >= MAX_FMTS)
+               return -EINVAL;
+
+       code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
+       return 0;
+}
+
+static int gc2235_enum_frame_size(struct v4l2_subdev *sd,
+                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_frame_size_enum *fse)
+{
+       int index = fse->index;
+
+       if (index >= N_RES)
+               return -EINVAL;
+
+       fse->min_width = gc2235_res[index].width;
+       fse->min_height = gc2235_res[index].height;
+       fse->max_width = gc2235_res[index].width;
+       fse->max_height = gc2235_res[index].height;
+
+       return 0;
+
+}
+
+static int gc2235_g_skip_frames(struct v4l2_subdev *sd, u32 *frames)
+{
+       struct gc2235_device *dev = to_gc2235_sensor(sd);
+
+       mutex_lock(&dev->input_lock);
+       *frames = gc2235_res[dev->fmt_idx].skip_frames;
+       mutex_unlock(&dev->input_lock);
+
+       return 0;
+}
+
+static const struct v4l2_subdev_sensor_ops gc2235_sensor_ops = {
+       .g_skip_frames  = gc2235_g_skip_frames,
+};
+
+static const struct v4l2_subdev_video_ops gc2235_video_ops = {
+       .s_stream = gc2235_s_stream,
+       .g_parm = gc2235_g_parm,
+       .s_parm = gc2235_s_parm,
+       .g_frame_interval = gc2235_g_frame_interval,
+};
+
+static const struct v4l2_subdev_core_ops gc2235_core_ops = {
+       .s_power = gc2235_s_power,
+       .ioctl = gc2235_ioctl,
+};
+
+static const struct v4l2_subdev_pad_ops gc2235_pad_ops = {
+       .enum_mbus_code = gc2235_enum_mbus_code,
+       .enum_frame_size = gc2235_enum_frame_size,
+       .get_fmt = gc2235_get_fmt,
+       .set_fmt = gc2235_set_fmt,
+};
+
+static const struct v4l2_subdev_ops gc2235_ops = {
+       .core = &gc2235_core_ops,
+       .video = &gc2235_video_ops,
+       .pad = &gc2235_pad_ops,
+       .sensor = &gc2235_sensor_ops,
+};
+
+static int gc2235_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct gc2235_device *dev = to_gc2235_sensor(sd);
+       dev_dbg(&client->dev, "gc2235_remove...\n");
+
+       if (dev->platform_data->platform_deinit)
+               dev->platform_data->platform_deinit();
+
+       dev->platform_data->csi_cfg(sd, 0);
+
+       v4l2_device_unregister_subdev(sd);
+       media_entity_cleanup(&dev->sd.entity);
+       v4l2_ctrl_handler_free(&dev->ctrl_handler);
+       kfree(dev);
+
+       return 0;
+}
+
+static int gc2235_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct gc2235_device *dev;
+       void *gcpdev;
+       int ret;
+       unsigned int i;
+
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev) {
+               dev_err(&client->dev, "out of memory\n");
+               return -ENOMEM;
+       }
+
+       mutex_init(&dev->input_lock);
+
+       dev->fmt_idx = 0;
+       v4l2_i2c_subdev_init(&(dev->sd), client, &gc2235_ops);
+
+       gcpdev = client->dev.platform_data;
+       if (ACPI_COMPANION(&client->dev))
+               gcpdev = gmin_camera_platform_data(&dev->sd,
+                                  ATOMISP_INPUT_FORMAT_RAW_10,
+                                  atomisp_bayer_order_grbg);
+
+       ret = gc2235_s_config(&dev->sd, client->irq, gcpdev);
+       if (ret)
+               goto out_free;
+
+       dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+       dev->pad.flags = MEDIA_PAD_FL_SOURCE;
+       dev->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
+       dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+       ret =
+           v4l2_ctrl_handler_init(&dev->ctrl_handler,
+                                  ARRAY_SIZE(gc2235_controls));
+       if (ret) {
+               gc2235_remove(client);
+               return ret;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(gc2235_controls); i++)
+               v4l2_ctrl_new_custom(&dev->ctrl_handler, &gc2235_controls[i],
+                                    NULL);
+
+       if (dev->ctrl_handler.error) {
+               gc2235_remove(client);
+               return dev->ctrl_handler.error;
+       }
+
+       /* Use same lock for controls as for everything else. */
+       dev->ctrl_handler.lock = &dev->input_lock;
+       dev->sd.ctrl_handler = &dev->ctrl_handler;
+
+       ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad);
+       if (ret)
+               gc2235_remove(client);
+
+       if (ACPI_HANDLE(&client->dev))
+               ret = atomisp_register_i2c_module(&dev->sd, gcpdev, RAW_CAMERA);
+
+       return ret;
+out_free:
+       v4l2_device_unregister_subdev(&dev->sd);
+       kfree(dev);
+
+       return ret;
+}
+
+static const struct acpi_device_id gc2235_acpi_match[] = {
+       { "INT33F8" },
+       {},
+};
+
+MODULE_DEVICE_TABLE(acpi, gc2235_acpi_match);
+MODULE_DEVICE_TABLE(i2c, gc2235_id);
+static struct i2c_driver gc2235_driver = {
+       .driver = {
+               .name = GC2235_NAME,
+               .acpi_match_table = ACPI_PTR(gc2235_acpi_match),
+       },
+       .probe = gc2235_probe,
+       .remove = gc2235_remove,
+       .id_table = gc2235_id,
+};
+
+static int init_gc2235(void)
+{
+       return i2c_add_driver(&gc2235_driver);
+}
+
+static void exit_gc2235(void)
+{
+
+       i2c_del_driver(&gc2235_driver);
+}
+
+module_init(init_gc2235);
+module_exit(exit_gc2235);
+
+MODULE_AUTHOR("Shuguang Gong <Shuguang.Gong@intel.com>");
+MODULE_DESCRIPTION("A low-level driver for GC2235 sensors");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-libmsrlisthelper.c b/drivers/staging/media/atomisp/i2c/atomisp-libmsrlisthelper.c
new file mode 100644 (file)
index 0000000..decb65c
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2013 Intel Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+#include <linux/i2c.h>
+#include <linux/firmware.h>
+#include <linux/device.h>
+#include <linux/export.h>
+#include "../include/linux/libmsrlisthelper.h"
+#include <linux/module.h>
+#include <linux/slab.h>
+
+/* Tagged binary data container structure definitions. */
+struct tbd_header {
+       uint32_t tag;          /*!< Tag identifier, also checks endianness */
+       uint32_t size;         /*!< Container size including this header */
+       uint32_t version;      /*!< Version, format 0xYYMMDDVV */
+       uint32_t revision;     /*!< Revision, format 0xYYMMDDVV */
+       uint32_t config_bits;  /*!< Configuration flag bits set */
+       uint32_t checksum;     /*!< Global checksum, header included */
+} __packed;
+
+struct tbd_record_header {
+       uint32_t size;        /*!< Size of record including header */
+       uint8_t format_id;    /*!< tbd_format_t enumeration values used */
+       uint8_t packing_key;  /*!< Packing method; 0 = no packing */
+       uint16_t class_id;    /*!< tbd_class_t enumeration values used */
+} __packed;
+
+struct tbd_data_record_header {
+       uint16_t next_offset;
+       uint16_t flags;
+       uint16_t data_offset;
+       uint16_t data_size;
+} __packed;
+
+#define TBD_CLASS_DRV_ID 2
+
+static int set_msr_configuration(struct i2c_client *client, uint8_t *bufptr,
+               unsigned int size)
+{
+       /* The configuration data contains any number of sequences where
+        * the first byte (that is, uint8_t) that marks the number of bytes
+        * in the sequence to follow, is indeed followed by the indicated
+        * number of bytes of actual data to be written to sensor.
+        * By convention, the first two bytes of actual data should be
+        * understood as an address in the sensor address space (hibyte
+        * followed by lobyte) where the remaining data in the sequence
+        * will be written. */
+
+       uint8_t *ptr = bufptr;
+       while (ptr < bufptr + size) {
+               struct i2c_msg msg = {
+                       .addr = client->addr,
+                       .flags = 0,
+               };
+               int ret;
+
+               /* How many bytes */
+               msg.len = *ptr++;
+               /* Where the bytes are located */
+               msg.buf = ptr;
+               ptr += msg.len;
+
+               if (ptr > bufptr + size)
+                       /* Accessing data beyond bounds is not tolerated */
+                       return -EINVAL;
+
+               ret = i2c_transfer(client->adapter, &msg, 1);
+               if (ret < 0) {
+                       dev_err(&client->dev, "i2c write error: %d", ret);
+                       return ret;
+               }
+       }
+       return 0;
+}
+
+static int parse_and_apply(struct i2c_client *client, uint8_t *buffer,
+               unsigned int size)
+{
+       uint8_t *endptr8 = buffer + size;
+       struct tbd_data_record_header *header =
+               (struct tbd_data_record_header *)buffer;
+
+       /* There may be any number of datasets present */
+       unsigned int dataset = 0;
+
+       do {
+               /* In below, four variables are read from buffer */
+               if ((uint8_t *)header + sizeof(*header) > endptr8)
+                       return -EINVAL;
+
+               /* All data should be located within given buffer */
+               if ((uint8_t *)header + header->data_offset +
+                               header->data_size > endptr8)
+                       return -EINVAL;
+
+               /* We have a new valid dataset */
+               dataset++;
+               /* See whether there is MSR data */
+               /* If yes, update the reg info */
+               if (header->data_size && (header->flags & 1)) {
+                       int ret;
+
+                       dev_info(&client->dev,
+                               "New MSR data for sensor driver (dataset %02d) size:%d\n",
+                               dataset, header->data_size);
+                       ret = set_msr_configuration(client,
+                                               buffer + header->data_offset,
+                                               header->data_size);
+                       if (ret)
+                               return ret;
+               }
+               header = (struct tbd_data_record_header *)(buffer +
+                       header->next_offset);
+       } while (header->next_offset);
+
+       return 0;
+}
+
+int apply_msr_data(struct i2c_client *client, const struct firmware *fw)
+{
+       struct tbd_header *header;
+       struct tbd_record_header *record;
+
+       if (!fw) {
+               dev_warn(&client->dev, "Drv data is not loaded.\n");
+               return -EINVAL;
+       }
+
+       if (sizeof(*header) > fw->size)
+               return -EINVAL;
+
+       header = (struct tbd_header *)fw->data;
+       /* Check that we have drvb block. */
+       if (memcmp(&header->tag, "DRVB", 4))
+               return -EINVAL;
+
+       /* Check the size */
+       if (header->size != fw->size)
+               return -EINVAL;
+
+       if (sizeof(*header) + sizeof(*record) > fw->size)
+               return -EINVAL;
+
+       record = (struct tbd_record_header *)(header + 1);
+       /* Check that class id mathes tbd's drv id. */
+       if (record->class_id != TBD_CLASS_DRV_ID)
+               return -EINVAL;
+
+       /* Size 0 shall not be treated as an error */
+       if (!record->size)
+               return 0;
+
+       return parse_and_apply(client, (uint8_t *)(record + 1), record->size);
+}
+EXPORT_SYMBOL_GPL(apply_msr_data);
+
+int load_msr_list(struct i2c_client *client, char *name,
+               const struct firmware **fw)
+{
+       int ret = request_firmware(fw, name, &client->dev);
+       if (ret) {
+               dev_err(&client->dev,
+                       "Error %d while requesting firmware %s\n",
+                       ret, name);
+               return ret;
+       }
+       dev_info(&client->dev, "Received %lu bytes drv data\n",
+                       (unsigned long)(*fw)->size);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(load_msr_list);
+
+void release_msr_list(struct i2c_client *client, const struct firmware *fw)
+{
+       release_firmware(fw);
+}
+EXPORT_SYMBOL_GPL(release_msr_list);
+
+static int init_msrlisthelper(void)
+{
+       return 0;
+}
+
+static void exit_msrlisthelper(void)
+{
+}
+
+module_init(init_msrlisthelper);
+module_exit(exit_msrlisthelper);
+
+MODULE_AUTHOR("Jukka Kaartinen <jukka.o.kaartinen@intel.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c b/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c
new file mode 100644 (file)
index 0000000..679176f
--- /dev/null
@@ -0,0 +1,1009 @@
+/*
+ * LED flash driver for LM3554
+ *
+ * Copyright (c) 2010-2012 Intel Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+
+#include "../include/media/lm3554.h"
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <linux/acpi.h>
+#include <linux/gpio/consumer.h>
+#include "../include/linux/atomisp_gmin_platform.h"
+#include "../include/linux/atomisp.h"
+
+/* Registers */
+
+#define LM3554_TORCH_BRIGHTNESS_REG    0xA0
+#define LM3554_TORCH_MODE_SHIFT                0
+#define LM3554_TORCH_CURRENT_SHIFT     3
+#define LM3554_INDICATOR_CURRENT_SHIFT 6
+
+#define LM3554_FLASH_BRIGHTNESS_REG    0xB0
+#define LM3554_FLASH_MODE_SHIFT                0
+#define LM3554_FLASH_CURRENT_SHIFT     3
+#define LM3554_STROBE_SENSITIVITY_SHIFT        7
+
+#define LM3554_FLASH_DURATION_REG      0xC0
+#define LM3554_FLASH_TIMEOUT_SHIFT     0
+#define LM3554_CURRENT_LIMIT_SHIFT     5
+
+#define LM3554_FLAGS_REG               0xD0
+#define LM3554_FLAG_TIMEOUT            (1 << 0)
+#define LM3554_FLAG_THERMAL_SHUTDOWN   (1 << 1)
+#define LM3554_FLAG_LED_FAULT          (1 << 2)
+#define LM3554_FLAG_TX1_INTERRUPT      (1 << 3)
+#define LM3554_FLAG_TX2_INTERRUPT      (1 << 4)
+#define LM3554_FLAG_LED_THERMAL_FAULT  (1 << 5)
+#define LM3554_FLAG_UNUSED             (1 << 6)
+#define LM3554_FLAG_INPUT_VOLTAGE_LOW  (1 << 7)
+
+#define LM3554_CONFIG_REG_1            0xE0
+#define LM3554_ENVM_TX2_SHIFT          5
+#define LM3554_TX2_POLARITY_SHIFT      6
+
+struct lm3554 {
+       struct v4l2_subdev sd;
+
+       struct mutex power_lock;
+       struct v4l2_ctrl_handler ctrl_handler;
+       int power_count;
+
+       unsigned int mode;
+       int timeout;
+       u8 torch_current;
+       u8 indicator_current;
+       u8 flash_current;
+
+       struct timer_list flash_off_delay;
+       struct lm3554_platform_data *pdata;
+};
+
+#define to_lm3554(p_sd)        container_of(p_sd, struct lm3554, sd)
+
+/* Return negative errno else zero on success */
+static int lm3554_write(struct lm3554 *flash, u8 addr, u8 val)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&flash->sd);
+       int ret;
+
+       ret = i2c_smbus_write_byte_data(client, addr, val);
+
+       dev_dbg(&client->dev, "Write Addr:%02X Val:%02X %s\n", addr, val,
+               ret < 0 ? "fail" : "ok");
+
+       return ret;
+}
+
+/* Return negative errno else a data byte received from the device. */
+static int lm3554_read(struct lm3554 *flash, u8 addr)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&flash->sd);
+       int ret;
+
+       ret = i2c_smbus_read_byte_data(client, addr);
+
+       dev_dbg(&client->dev, "Read Addr:%02X Val:%02X %s\n", addr, ret,
+               ret < 0 ? "fail" : "ok");
+
+       return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * Hardware configuration
+ */
+
+static int lm3554_set_mode(struct lm3554 *flash, unsigned int mode)
+{
+       u8 val;
+       int ret;
+
+       val = (mode << LM3554_FLASH_MODE_SHIFT) |
+             (flash->flash_current << LM3554_FLASH_CURRENT_SHIFT);
+
+       ret = lm3554_write(flash, LM3554_FLASH_BRIGHTNESS_REG, val);
+       if (ret == 0)
+               flash->mode = mode;
+       return ret;
+}
+
+static int lm3554_set_torch(struct lm3554 *flash)
+{
+       u8 val;
+
+       val = (flash->mode << LM3554_TORCH_MODE_SHIFT) |
+             (flash->torch_current << LM3554_TORCH_CURRENT_SHIFT) |
+             (flash->indicator_current << LM3554_INDICATOR_CURRENT_SHIFT);
+
+       return lm3554_write(flash, LM3554_TORCH_BRIGHTNESS_REG, val);
+}
+
+static int lm3554_set_flash(struct lm3554 *flash)
+{
+       u8 val;
+
+       val = (flash->mode << LM3554_FLASH_MODE_SHIFT) |
+             (flash->flash_current << LM3554_FLASH_CURRENT_SHIFT);
+
+       return lm3554_write(flash, LM3554_FLASH_BRIGHTNESS_REG, val);
+}
+
+static int lm3554_set_duration(struct lm3554 *flash)
+{
+       u8 val;
+
+       val = (flash->timeout << LM3554_FLASH_TIMEOUT_SHIFT) |
+             (flash->pdata->current_limit << LM3554_CURRENT_LIMIT_SHIFT);
+
+       return lm3554_write(flash, LM3554_FLASH_DURATION_REG, val);
+}
+
+static int lm3554_set_config1(struct lm3554 *flash)
+{
+       u8 val;
+
+       val = (flash->pdata->envm_tx2 << LM3554_ENVM_TX2_SHIFT) |
+             (flash->pdata->tx2_polarity << LM3554_TX2_POLARITY_SHIFT);
+       return lm3554_write(flash, LM3554_CONFIG_REG_1, val);
+}
+
+/* -----------------------------------------------------------------------------
+ * Hardware trigger
+ */
+static void lm3554_flash_off_delay(long unsigned int arg)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata((struct i2c_client *)arg);
+       struct lm3554 *flash = to_lm3554(sd);
+       struct lm3554_platform_data *pdata = flash->pdata;
+
+       gpio_set_value(pdata->gpio_strobe, 0);
+}
+
+static int lm3554_hw_strobe(struct i2c_client *client, bool strobe)
+{
+       int ret, timer_pending;
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct lm3554 *flash = to_lm3554(sd);
+       struct lm3554_platform_data *pdata = flash->pdata;
+
+       /*
+        * An abnormal high flash current is observed when strobe off the
+        * flash. Workaround here is firstly set flash current to lower level,
+        * wait a short moment, and then strobe off the flash.
+        */
+
+       timer_pending = del_timer_sync(&flash->flash_off_delay);
+
+       /* Flash off */
+       if (!strobe) {
+               /* set current to 70mA and wait a while */
+               ret = lm3554_write(flash, LM3554_FLASH_BRIGHTNESS_REG, 0);
+               if (ret < 0)
+                       goto err;
+               mod_timer(&flash->flash_off_delay,
+                         jiffies + msecs_to_jiffies(LM3554_TIMER_DELAY));
+               return 0;
+       }
+
+       /* Flash on */
+
+       /*
+        * If timer is killed before run, flash is not strobe off,
+        * so must strobe off here
+        */
+       if (timer_pending)
+               gpio_set_value(pdata->gpio_strobe, 0);
+
+       /* Restore flash current settings */
+       ret = lm3554_set_flash(flash);
+       if (ret < 0)
+               goto err;
+
+       /* Strobe on Flash */
+       gpio_set_value(pdata->gpio_strobe, 1);
+
+       return 0;
+err:
+       dev_err(&client->dev, "failed to %s flash strobe (%d)\n",
+               strobe ? "on" : "off", ret);
+       return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 controls
+ */
+
+static int lm3554_read_status(struct lm3554 *flash)
+{
+       int ret;
+       struct i2c_client *client = v4l2_get_subdevdata(&flash->sd);
+
+       /* NOTE: reading register clear fault status */
+       ret = lm3554_read(flash, LM3554_FLAGS_REG);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * Accordingly to datasheet we read back '1' in bit 6.
+        * Clear it first.
+        */
+       ret &= ~LM3554_FLAG_UNUSED;
+
+       /*
+        * Do not take TX1/TX2 signal as an error
+        * because MSIC will not turn off flash, but turn to
+        * torch mode according to gsm modem signal by hardware.
+        */
+       ret &= ~(LM3554_FLAG_TX1_INTERRUPT | LM3554_FLAG_TX2_INTERRUPT);
+
+       if (ret > 0)
+               dev_dbg(&client->dev, "LM3554 flag status: %02x\n", ret);
+
+       return ret;
+}
+
+static int lm3554_s_flash_timeout(struct v4l2_subdev *sd, u32 val)
+{
+       struct lm3554 *flash = to_lm3554(sd);
+
+       val = clamp(val, LM3554_MIN_TIMEOUT, LM3554_MAX_TIMEOUT);
+       val = val / LM3554_TIMEOUT_STEPSIZE - 1;
+
+       flash->timeout = val;
+
+       return lm3554_set_duration(flash);
+}
+
+static int lm3554_g_flash_timeout(struct v4l2_subdev *sd, s32 *val)
+{
+       struct lm3554 *flash = to_lm3554(sd);
+
+       *val = (u32)(flash->timeout + 1) * LM3554_TIMEOUT_STEPSIZE;
+
+       return 0;
+}
+
+static int lm3554_s_flash_intensity(struct v4l2_subdev *sd, u32 intensity)
+{
+       struct lm3554 *flash = to_lm3554(sd);
+
+       intensity = LM3554_CLAMP_PERCENTAGE(intensity);
+       intensity = LM3554_PERCENT_TO_VALUE(intensity, LM3554_FLASH_STEP);
+
+       flash->flash_current = intensity;
+
+       return lm3554_set_flash(flash);
+}
+
+static int lm3554_g_flash_intensity(struct v4l2_subdev *sd, s32 *val)
+{
+       struct lm3554 *flash = to_lm3554(sd);
+
+       *val = LM3554_VALUE_TO_PERCENT((u32)flash->flash_current,
+                       LM3554_FLASH_STEP);
+
+       return 0;
+}
+
+static int lm3554_s_torch_intensity(struct v4l2_subdev *sd, u32 intensity)
+{
+       struct lm3554 *flash = to_lm3554(sd);
+
+       intensity = LM3554_CLAMP_PERCENTAGE(intensity);
+       intensity = LM3554_PERCENT_TO_VALUE(intensity, LM3554_TORCH_STEP);
+
+       flash->torch_current = intensity;
+
+       return lm3554_set_torch(flash);
+}
+
+static int lm3554_g_torch_intensity(struct v4l2_subdev *sd, s32 *val)
+{
+       struct lm3554 *flash = to_lm3554(sd);
+
+       *val = LM3554_VALUE_TO_PERCENT((u32)flash->torch_current,
+                       LM3554_TORCH_STEP);
+
+       return 0;
+}
+
+static int lm3554_s_indicator_intensity(struct v4l2_subdev *sd, u32 intensity)
+{
+       struct lm3554 *flash = to_lm3554(sd);
+
+       intensity = LM3554_CLAMP_PERCENTAGE(intensity);
+       intensity = LM3554_PERCENT_TO_VALUE(intensity, LM3554_INDICATOR_STEP);
+
+       flash->indicator_current = intensity;
+
+       return lm3554_set_torch(flash);
+}
+
+static int lm3554_g_indicator_intensity(struct v4l2_subdev *sd, s32 *val)
+{
+       struct lm3554 *flash = to_lm3554(sd);
+
+       *val = LM3554_VALUE_TO_PERCENT((u32)flash->indicator_current,
+                       LM3554_INDICATOR_STEP);
+
+       return 0;
+}
+
+static int lm3554_s_flash_strobe(struct v4l2_subdev *sd, u32 val)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return lm3554_hw_strobe(client, val);
+}
+
+static int lm3554_s_flash_mode(struct v4l2_subdev *sd, u32 new_mode)
+{
+       struct lm3554 *flash = to_lm3554(sd);
+       unsigned int mode;
+
+       switch (new_mode) {
+       case ATOMISP_FLASH_MODE_OFF:
+               mode = LM3554_MODE_SHUTDOWN;
+               break;
+       case ATOMISP_FLASH_MODE_FLASH:
+               mode = LM3554_MODE_FLASH;
+               break;
+       case ATOMISP_FLASH_MODE_INDICATOR:
+               mode = LM3554_MODE_INDICATOR;
+               break;
+       case ATOMISP_FLASH_MODE_TORCH:
+               mode = LM3554_MODE_TORCH;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return lm3554_set_mode(flash, mode);
+}
+
+static int lm3554_g_flash_mode(struct v4l2_subdev *sd, s32 *val)
+{
+       struct lm3554 *flash = to_lm3554(sd);
+       *val = flash->mode;
+       return 0;
+}
+
+static int lm3554_g_flash_status(struct v4l2_subdev *sd, s32 *val)
+{
+       struct lm3554 *flash = to_lm3554(sd);
+       int value;
+
+       value = lm3554_read_status(flash);
+       if (value < 0)
+               return value;
+
+       if (value & LM3554_FLAG_TIMEOUT)
+               *val = ATOMISP_FLASH_STATUS_TIMEOUT;
+       else if (value > 0)
+               *val = ATOMISP_FLASH_STATUS_HW_ERROR;
+       else
+               *val = ATOMISP_FLASH_STATUS_OK;
+
+       return 0;
+}
+
+#ifndef CSS15
+static int lm3554_g_flash_status_register(struct v4l2_subdev *sd, s32 *val)
+{
+       struct lm3554 *flash = to_lm3554(sd);
+       int ret;
+
+       ret = lm3554_read(flash, LM3554_FLAGS_REG);
+
+       if (ret < 0)
+               return ret;
+
+       *val = ret;
+       return 0;
+}
+#endif
+
+static int lm3554_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct lm3554 *dev =
+           container_of(ctrl->handler, struct lm3554, ctrl_handler);
+       int ret = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_FLASH_TIMEOUT:
+               ret = lm3554_s_flash_timeout(&dev->sd, ctrl->val);
+               break;
+       case V4L2_CID_FLASH_INTENSITY:
+               ret = lm3554_s_flash_intensity(&dev->sd, ctrl->val);
+               break;
+       case V4L2_CID_FLASH_TORCH_INTENSITY:
+               ret = lm3554_s_torch_intensity(&dev->sd, ctrl->val);
+               break;
+       case V4L2_CID_FLASH_INDICATOR_INTENSITY:
+               ret = lm3554_s_indicator_intensity(&dev->sd, ctrl->val);
+               break;
+       case V4L2_CID_FLASH_STROBE:
+               ret = lm3554_s_flash_strobe(&dev->sd, ctrl->val);
+               break;
+       case V4L2_CID_FLASH_MODE:
+               ret = lm3554_s_flash_mode(&dev->sd, ctrl->val);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+       return ret;
+}
+
+static int lm3554_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct lm3554 *dev =
+           container_of(ctrl->handler, struct lm3554, ctrl_handler);
+       int ret = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_FLASH_TIMEOUT:
+               ret = lm3554_g_flash_timeout(&dev->sd, &ctrl->val);
+               break;
+       case V4L2_CID_FLASH_INTENSITY:
+               ret = lm3554_g_flash_intensity(&dev->sd, &ctrl->val);
+               break;
+       case V4L2_CID_FLASH_TORCH_INTENSITY:
+               ret = lm3554_g_torch_intensity(&dev->sd, &ctrl->val);
+               break;
+       case V4L2_CID_FLASH_INDICATOR_INTENSITY:
+               ret = lm3554_g_indicator_intensity(&dev->sd, &ctrl->val);
+               break;
+       case V4L2_CID_FLASH_MODE:
+               ret = lm3554_g_flash_mode(&dev->sd, &ctrl->val);
+               break;
+       case V4L2_CID_FLASH_STATUS:
+               ret = lm3554_g_flash_status(&dev->sd, &ctrl->val);
+               break;
+#ifndef CSS15
+       case V4L2_CID_FLASH_STATUS_REGISTER:
+               ret = lm3554_g_flash_status_register(&dev->sd, &ctrl->val);
+               break;
+#endif
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static const struct v4l2_ctrl_ops ctrl_ops = {
+       .s_ctrl = lm3554_s_ctrl,
+       .g_volatile_ctrl = lm3554_g_volatile_ctrl
+};
+
+static const struct v4l2_ctrl_config lm3554_controls[] = {
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_FLASH_TIMEOUT,
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .name = "Flash Timeout",
+        .min = 0x0,
+        .max = LM3554_MAX_TIMEOUT,
+        .step = 0x01,
+        .def = LM3554_DEFAULT_TIMEOUT,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_FLASH_INTENSITY,
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .name = "Flash Intensity",
+        .min = LM3554_MIN_PERCENT,
+        .max = LM3554_MAX_PERCENT,
+        .step = 0x01,
+        .def = LM3554_FLASH_DEFAULT_BRIGHTNESS,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_FLASH_TORCH_INTENSITY,
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .name = "Torch Intensity",
+        .min = LM3554_MIN_PERCENT,
+        .max = LM3554_MAX_PERCENT,
+        .step = 0x01,
+        .def = LM3554_TORCH_DEFAULT_BRIGHTNESS,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_FLASH_INDICATOR_INTENSITY,
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .name = "Indicator Intensity",
+        .min = LM3554_MIN_PERCENT,
+        .max = LM3554_MAX_PERCENT,
+        .step = 0x01,
+        .def = LM3554_INDICATOR_DEFAULT_BRIGHTNESS,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_FLASH_STROBE,
+        .type = V4L2_CTRL_TYPE_BOOLEAN,
+        .name = "Flash Strobe",
+        .min = 0,
+        .max = 1,
+        .step = 1,
+        .def = 0,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_FLASH_MODE,
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .name = "Flash Mode",
+        .min = 0,
+        .max = 100,
+        .step = 1,
+        .def = ATOMISP_FLASH_MODE_OFF,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_FLASH_STATUS,
+        .type = V4L2_CTRL_TYPE_BOOLEAN,
+        .name = "Flash Status",
+        .min = 0,
+        .max = 100,
+        .step = 1,
+        .def = ATOMISP_FLASH_STATUS_OK,
+        .flags = 0,
+        },
+#ifndef CSS15
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_FLASH_STATUS_REGISTER,
+        .type = V4L2_CTRL_TYPE_BOOLEAN,
+        .name = "Flash Status Register",
+        .min = 0,
+        .max = 100,
+        .step = 1,
+        .def = 0,
+        .flags = 0,
+        },
+#endif
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev core operations
+ */
+
+/* Put device into known state. */
+static int lm3554_setup(struct lm3554 *flash)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(&flash->sd);
+       int ret;
+
+       /* clear the flags register */
+       ret = lm3554_read(flash, LM3554_FLAGS_REG);
+       if (ret < 0)
+               return ret;
+
+       dev_dbg(&client->dev, "Fault info: %02x\n", ret);
+
+       ret = lm3554_set_config1(flash);
+       if (ret < 0)
+               return ret;
+
+       ret = lm3554_set_duration(flash);
+       if (ret < 0)
+               return ret;
+
+       ret = lm3554_set_torch(flash);
+       if (ret < 0)
+               return ret;
+
+       ret = lm3554_set_flash(flash);
+       if (ret < 0)
+               return ret;
+
+       /* read status */
+       ret = lm3554_read_status(flash);
+       if (ret < 0)
+               return ret;
+
+       return ret ? -EIO : 0;
+}
+
+static int __lm3554_s_power(struct lm3554 *flash, int power)
+{
+       struct lm3554_platform_data *pdata = flash->pdata;
+       int ret;
+
+       /*initialize flash driver*/
+       gpio_set_value(pdata->gpio_reset, power);
+       usleep_range(100, 100 + 1);
+
+       if (power) {
+               /* Setup default values. This makes sure that the chip
+                * is in a known state.
+                */
+               ret = lm3554_setup(flash);
+               if (ret < 0) {
+                       __lm3554_s_power(flash, 0);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int lm3554_s_power(struct v4l2_subdev *sd, int power)
+{
+       struct lm3554 *flash = to_lm3554(sd);
+       int ret = 0;
+
+       mutex_lock(&flash->power_lock);
+
+       if (flash->power_count == !power) {
+               ret = __lm3554_s_power(flash, !!power);
+               if (ret < 0)
+                       goto done;
+       }
+
+       flash->power_count += power ? 1 : -1;
+       WARN_ON(flash->power_count < 0);
+
+done:
+       mutex_unlock(&flash->power_lock);
+       return ret;
+}
+
+static const struct v4l2_subdev_core_ops lm3554_core_ops = {
+       .s_power = lm3554_s_power,
+};
+
+static const struct v4l2_subdev_ops lm3554_ops = {
+       .core = &lm3554_core_ops,
+};
+
+static int lm3554_detect(struct v4l2_subdev *sd)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct i2c_adapter *adapter = client->adapter;
+       struct lm3554 *flash = to_lm3554(sd);
+       int ret;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+               dev_err(&client->dev, "lm3554_detect i2c error\n");
+               return -ENODEV;
+       }
+
+       /* Power up the flash driver and reset it */
+       ret = lm3554_s_power(&flash->sd, 1);
+       if (ret < 0) {
+               dev_err(&client->dev, "Failed to power on lm3554 LED flash\n");
+       } else {
+               dev_dbg(&client->dev, "Successfully detected lm3554 LED flash\n");
+               lm3554_s_power(&flash->sd, 0);
+       }
+
+       return ret;
+}
+
+static int lm3554_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+       return lm3554_s_power(sd, 1);
+}
+
+static int lm3554_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+       return lm3554_s_power(sd, 0);
+}
+
+static const struct v4l2_subdev_internal_ops lm3554_internal_ops = {
+       .registered = lm3554_detect,
+       .open = lm3554_open,
+       .close = lm3554_close,
+};
+
+/* -----------------------------------------------------------------------------
+ *  I2C driver
+ */
+#ifdef CONFIG_PM
+
+static int lm3554_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+       struct lm3554 *flash = to_lm3554(subdev);
+       int rval;
+
+       if (flash->power_count == 0)
+               return 0;
+
+       rval = __lm3554_s_power(flash, 0);
+
+       dev_dbg(&client->dev, "Suspend %s\n", rval < 0 ? "failed" : "ok");
+
+       return rval;
+}
+
+static int lm3554_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+       struct lm3554 *flash = to_lm3554(subdev);
+       int rval;
+
+       if (flash->power_count == 0)
+               return 0;
+
+       rval = __lm3554_s_power(flash, 1);
+
+       dev_dbg(&client->dev, "Resume %s\n", rval < 0 ? "fail" : "ok");
+
+       return rval;
+}
+
+#else
+
+#define lm3554_suspend NULL
+#define lm3554_resume  NULL
+
+#endif /* CONFIG_PM */
+
+static int lm3554_gpio_init(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct lm3554 *flash = to_lm3554(sd);
+       struct lm3554_platform_data *pdata = flash->pdata;
+       int ret;
+
+       if (!gpio_is_valid(pdata->gpio_reset))
+               return -EINVAL;
+
+       ret = gpio_direction_output(pdata->gpio_reset, 0);
+       if (ret < 0)
+               goto err_gpio_reset;
+       dev_info(&client->dev, "flash led reset successfully\n");
+
+       if (!gpio_is_valid(pdata->gpio_strobe)) {
+               ret = -EINVAL;
+               goto err_gpio_dir_reset;
+       }
+
+       ret = gpio_direction_output(pdata->gpio_strobe, 0);
+       if (ret < 0)
+               goto err_gpio_strobe;
+
+       return 0;
+
+err_gpio_strobe:
+       gpio_free(pdata->gpio_strobe);
+err_gpio_dir_reset:
+       gpio_direction_output(pdata->gpio_reset, 0);
+err_gpio_reset:
+       gpio_free(pdata->gpio_reset);
+
+       return ret;
+}
+
+static int lm3554_gpio_uninit(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct lm3554 *flash = to_lm3554(sd);
+       struct lm3554_platform_data *pdata = flash->pdata;
+       int ret;
+
+       ret = gpio_direction_output(pdata->gpio_strobe, 0);
+       if (ret < 0)
+               return ret;
+
+       ret = gpio_direction_output(pdata->gpio_reset, 0);
+       if (ret < 0)
+               return ret;
+
+       gpio_free(pdata->gpio_strobe);
+       gpio_free(pdata->gpio_reset);
+       return 0;
+}
+
+static void *lm3554_platform_data_func(struct i2c_client *client)
+{
+       static struct lm3554_platform_data platform_data;
+
+       if (ACPI_COMPANION(&client->dev)) {
+               platform_data.gpio_reset =
+                   desc_to_gpio(gpiod_get_index(&(client->dev),
+                                                NULL, 2, GPIOD_OUT_LOW));
+               platform_data.gpio_strobe =
+                   desc_to_gpio(gpiod_get_index(&(client->dev),
+                                                NULL, 0, GPIOD_OUT_LOW));
+               platform_data.gpio_torch =
+                   desc_to_gpio(gpiod_get_index(&(client->dev),
+                                                NULL, 1, GPIOD_OUT_LOW));
+       } else {
+               platform_data.gpio_reset = -1;
+               platform_data.gpio_strobe = -1;
+               platform_data.gpio_torch = -1;
+       }
+
+       dev_info(&client->dev, "camera pdata: lm3554: reset: %d strobe %d torch %d\n",
+               platform_data.gpio_reset, platform_data.gpio_strobe,
+               platform_data.gpio_torch);
+
+       /* Set to TX2 mode, then ENVM/TX2 pin is a power amplifier sync input:
+        * ENVM/TX pin asserted, flash forced into torch;
+        * ENVM/TX pin desserted, flash set back;
+        */
+       platform_data.envm_tx2 = 1;
+       platform_data.tx2_polarity = 0;
+
+       /* set peak current limit to be 1000mA */
+       platform_data.current_limit = 0;
+
+       return &platform_data;
+}
+
+static int lm3554_probe(struct i2c_client *client,
+                                 const struct i2c_device_id *id)
+{
+       int err = 0;
+       struct lm3554 *flash;
+       unsigned int i;
+       int ret;
+
+       flash = kzalloc(sizeof(*flash), GFP_KERNEL);
+       if (!flash) {
+               dev_err(&client->dev, "out of memory\n");
+               return -ENOMEM;
+       }
+
+       flash->pdata = client->dev.platform_data;
+
+       if (!flash->pdata || ACPI_COMPANION(&client->dev))
+               flash->pdata = lm3554_platform_data_func(client);
+
+       v4l2_i2c_subdev_init(&flash->sd, client, &lm3554_ops);
+       flash->sd.internal_ops = &lm3554_internal_ops;
+       flash->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+       flash->mode = ATOMISP_FLASH_MODE_OFF;
+       flash->timeout = LM3554_MAX_TIMEOUT / LM3554_TIMEOUT_STEPSIZE - 1;
+       ret =
+           v4l2_ctrl_handler_init(&flash->ctrl_handler,
+                                  ARRAY_SIZE(lm3554_controls));
+       if (ret) {
+               dev_err(&client->dev, "error initialize a ctrl_handler.\n");
+               goto fail2;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(lm3554_controls); i++)
+               v4l2_ctrl_new_custom(&flash->ctrl_handler, &lm3554_controls[i],
+                                    NULL);
+
+       if (flash->ctrl_handler.error) {
+
+               dev_err(&client->dev, "ctrl_handler error.\n");
+               goto fail2;
+       }
+
+       flash->sd.ctrl_handler = &flash->ctrl_handler;
+       err = media_entity_pads_init(&flash->sd.entity, 0, NULL);
+       if (err) {
+               dev_err(&client->dev, "error initialize a media entity.\n");
+               goto fail1;
+       }
+
+       flash->sd.entity.function = MEDIA_ENT_F_FLASH;
+
+       mutex_init(&flash->power_lock);
+
+       setup_timer(&flash->flash_off_delay, lm3554_flash_off_delay,
+                   (unsigned long)client);
+
+       err = lm3554_gpio_init(client);
+       if (err) {
+               dev_err(&client->dev, "gpio request/direction_output fail");
+               goto fail2;
+       }
+       if (ACPI_HANDLE(&client->dev))
+               err = atomisp_register_i2c_module(&flash->sd, NULL, LED_FLASH);
+       return 0;
+fail2:
+       media_entity_cleanup(&flash->sd.entity);
+       v4l2_ctrl_handler_free(&flash->ctrl_handler);
+fail1:
+       v4l2_device_unregister_subdev(&flash->sd);
+       kfree(flash);
+
+       return err;
+}
+
+static int lm3554_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct lm3554 *flash = to_lm3554(sd);
+       int ret;
+
+       media_entity_cleanup(&flash->sd.entity);
+       v4l2_ctrl_handler_free(&flash->ctrl_handler);
+       v4l2_device_unregister_subdev(sd);
+
+       atomisp_gmin_remove_subdev(sd);
+
+       del_timer_sync(&flash->flash_off_delay);
+
+       ret = lm3554_gpio_uninit(client);
+       if (ret < 0)
+               goto fail;
+
+       kfree(flash);
+
+       return 0;
+fail:
+       dev_err(&client->dev, "gpio request/direction_output fail");
+       return ret;
+}
+
+static const struct i2c_device_id lm3554_id[] = {
+       {LM3554_NAME, 0},
+       {},
+};
+
+MODULE_DEVICE_TABLE(i2c, lm3554_id);
+
+static const struct dev_pm_ops lm3554_pm_ops = {
+       .suspend = lm3554_suspend,
+       .resume = lm3554_resume,
+};
+
+static const struct acpi_device_id lm3554_acpi_match[] = {
+       { "INTCF1C" },
+       {},
+};
+
+MODULE_DEVICE_TABLE(acpi, lm3554_acpi_match);
+
+static struct i2c_driver lm3554_driver = {
+       .driver = {
+               .name = LM3554_NAME,
+               .pm   = &lm3554_pm_ops,
+               .acpi_match_table = ACPI_PTR(lm3554_acpi_match),
+       },
+       .probe = lm3554_probe,
+       .remove = lm3554_remove,
+       .id_table = lm3554_id,
+};
+
+static __init int init_lm3554(void)
+{
+       return i2c_add_driver(&lm3554_driver);
+}
+
+static __exit void exit_lm3554(void)
+{
+       i2c_del_driver(&lm3554_driver);
+}
+
+module_init(init_lm3554);
+module_exit(exit_lm3554);
+MODULE_AUTHOR("Jing Tao <jing.tao@intel.com>");
+MODULE_DESCRIPTION("LED flash driver for LM3554");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c
new file mode 100644 (file)
index 0000000..3c837cb
--- /dev/null
@@ -0,0 +1,1963 @@
+/*
+ * Support for mt9m114 Camera Sensor.
+ *
+ * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kmod.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/acpi.h>
+#include "../include/linux/atomisp_gmin_platform.h"
+#include <media/v4l2-device.h>
+
+#include "mt9m114.h"
+
+#define to_mt9m114_sensor(sd) container_of(sd, struct mt9m114_device, sd)
+
+/*
+ * TODO: use debug parameter to actually define when debug messages should
+ * be printed.
+ */
+static int debug;
+static int aaalock;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+static int mt9m114_t_vflip(struct v4l2_subdev *sd, int value);
+static int mt9m114_t_hflip(struct v4l2_subdev *sd, int value);
+static int mt9m114_wait_state(struct i2c_client *client, int timeout);
+
+static int
+mt9m114_read_reg(struct i2c_client *client, u16 data_length, u32 reg, u32 *val)
+{
+       int err;
+       struct i2c_msg msg[2];
+       unsigned char data[4];
+
+       if (!client->adapter) {
+               v4l2_err(client, "%s error, no client->adapter\n", __func__);
+               return -ENODEV;
+       }
+
+       if (data_length != MISENSOR_8BIT && data_length != MISENSOR_16BIT
+                                        && data_length != MISENSOR_32BIT) {
+               v4l2_err(client, "%s error, invalid data length\n", __func__);
+               return -EINVAL;
+       }
+
+       msg[0].addr = client->addr;
+       msg[0].flags = 0;
+       msg[0].len = MSG_LEN_OFFSET;
+       msg[0].buf = data;
+
+       /* high byte goes out first */
+       data[0] = (u16) (reg >> 8);
+       data[1] = (u16) (reg & 0xff);
+
+       msg[1].addr = client->addr;
+       msg[1].len = data_length;
+       msg[1].flags = I2C_M_RD;
+       msg[1].buf = data;
+
+       err = i2c_transfer(client->adapter, msg, 2);
+
+       if (err >= 0) {
+               *val = 0;
+               /* high byte comes first */
+               if (data_length == MISENSOR_8BIT)
+                       *val = data[0];
+               else if (data_length == MISENSOR_16BIT)
+                       *val = data[1] + (data[0] << 8);
+               else
+                       *val = data[3] + (data[2] << 8) +
+                           (data[1] << 16) + (data[0] << 24);
+
+               return 0;
+       }
+
+       dev_err(&client->dev, "read from offset 0x%x error %d", reg, err);
+       return err;
+}
+
+static int
+mt9m114_write_reg(struct i2c_client *client, u16 data_length, u16 reg, u32 val)
+{
+       int num_msg;
+       struct i2c_msg msg;
+       unsigned char data[6] = {0};
+       u16 *wreg;
+       int retry = 0;
+
+       if (!client->adapter) {
+               v4l2_err(client, "%s error, no client->adapter\n", __func__);
+               return -ENODEV;
+       }
+
+       if (data_length != MISENSOR_8BIT && data_length != MISENSOR_16BIT
+                                        && data_length != MISENSOR_32BIT) {
+               v4l2_err(client, "%s error, invalid data_length\n", __func__);
+               return -EINVAL;
+       }
+
+       memset(&msg, 0, sizeof(msg));
+
+again:
+       msg.addr = client->addr;
+       msg.flags = 0;
+       msg.len = 2 + data_length;
+       msg.buf = data;
+
+       /* high byte goes out first */
+       wreg = (u16 *)data;
+       *wreg = cpu_to_be16(reg);
+
+       if (data_length == MISENSOR_8BIT) {
+               data[2] = (u8)(val);
+       } else if (data_length == MISENSOR_16BIT) {
+               u16 *wdata = (u16 *)&data[2];
+               *wdata = be16_to_cpu((u16)val);
+       } else {
+               /* MISENSOR_32BIT */
+               u32 *wdata = (u32 *)&data[2];
+               *wdata = be32_to_cpu(val);
+       }
+
+       num_msg = i2c_transfer(client->adapter, &msg, 1);
+
+       /*
+        * HACK: Need some delay here for Rev 2 sensors otherwise some
+        * registers do not seem to load correctly.
+        */
+       mdelay(1);
+
+       if (num_msg >= 0)
+               return 0;
+
+       dev_err(&client->dev, "write error: wrote 0x%x to offset 0x%x error %d",
+               val, reg, num_msg);
+       if (retry <= I2C_RETRY_COUNT) {
+               dev_dbg(&client->dev, "retrying... %d", retry);
+               retry++;
+               msleep(20);
+               goto again;
+       }
+
+       return num_msg;
+}
+
+/**
+ * misensor_rmw_reg - Read/Modify/Write a value to a register in the sensor
+ * device
+ * @client: i2c driver client structure
+ * @data_length: 8/16/32-bits length
+ * @reg: register address
+ * @mask: masked out bits
+ * @set: bits set
+ *
+ * Read/modify/write a value to a register in the  sensor device.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int
+misensor_rmw_reg(struct i2c_client *client, u16 data_length, u16 reg,
+                    u32 mask, u32 set)
+{
+       int err;
+       u32 val;
+
+       /* Exit when no mask */
+       if (mask == 0)
+               return 0;
+
+       /* @mask must not exceed data length */
+       switch (data_length) {
+       case MISENSOR_8BIT:
+               if (mask & ~0xff)
+                       return -EINVAL;
+               break;
+       case MISENSOR_16BIT:
+               if (mask & ~0xffff)
+                       return -EINVAL;
+               break;
+       case MISENSOR_32BIT:
+               break;
+       default:
+               /* Wrong @data_length */
+               return -EINVAL;
+       }
+
+       err = mt9m114_read_reg(client, data_length, reg, &val);
+       if (err) {
+               v4l2_err(client, "misensor_rmw_reg error exit, read failed\n");
+               return -EINVAL;
+       }
+
+       val &= ~mask;
+
+       /*
+        * Perform the OR function if the @set exists.
+        * Shift @set value to target bit location. @set should set only
+        * bits included in @mask.
+        *
+        * REVISIT: This function expects @set to be non-shifted. Its shift
+        * value is then defined to be equal to mask's LSB position.
+        * How about to inform values in their right offset position and avoid
+        * this unneeded shift operation?
+        */
+       set <<= ffs(mask) - 1;
+       val |= set & mask;
+
+       err = mt9m114_write_reg(client, data_length, reg, val);
+       if (err) {
+               v4l2_err(client, "misensor_rmw_reg error exit, write failed\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+
+static int __mt9m114_flush_reg_array(struct i2c_client *client,
+                                    struct mt9m114_write_ctrl *ctrl)
+{
+       struct i2c_msg msg;
+       const int num_msg = 1;
+       int ret;
+       int retry = 0;
+
+       if (ctrl->index == 0)
+               return 0;
+
+again:
+       msg.addr = client->addr;
+       msg.flags = 0;
+       msg.len = 2 + ctrl->index;
+       ctrl->buffer.addr = cpu_to_be16(ctrl->buffer.addr);
+       msg.buf = (u8 *)&ctrl->buffer;
+
+       ret = i2c_transfer(client->adapter, &msg, num_msg);
+       if (ret != num_msg) {
+               if (++retry <= I2C_RETRY_COUNT) {
+                       dev_dbg(&client->dev, "retrying... %d\n", retry);
+                       msleep(20);
+                       goto again;
+               }
+               dev_err(&client->dev, "%s: i2c transfer error\n", __func__);
+               return -EIO;
+       }
+
+       ctrl->index = 0;
+
+       /*
+        * REVISIT: Previously we had a delay after writing data to sensor.
+        * But it was removed as our tests have shown it is not necessary
+        * anymore.
+        */
+
+       return 0;
+}
+
+static int __mt9m114_buf_reg_array(struct i2c_client *client,
+                                  struct mt9m114_write_ctrl *ctrl,
+                                  const struct misensor_reg *next)
+{
+       u16 *data16;
+       u32 *data32;
+       int err;
+
+       /* Insufficient buffer? Let's flush and get more free space. */
+       if (ctrl->index + next->length >= MT9M114_MAX_WRITE_BUF_SIZE) {
+               err = __mt9m114_flush_reg_array(client, ctrl);
+               if (err)
+                       return err;
+       }
+
+       switch (next->length) {
+       case MISENSOR_8BIT:
+               ctrl->buffer.data[ctrl->index] = (u8)next->val;
+               break;
+       case MISENSOR_16BIT:
+               data16 = (u16 *)&ctrl->buffer.data[ctrl->index];
+               *data16 = cpu_to_be16((u16)next->val);
+               break;
+       case MISENSOR_32BIT:
+               data32 = (u32 *)&ctrl->buffer.data[ctrl->index];
+               *data32 = cpu_to_be32(next->val);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* When first item is added, we need to store its starting address */
+       if (ctrl->index == 0)
+               ctrl->buffer.addr = next->reg;
+
+       ctrl->index += next->length;
+
+       return 0;
+}
+
+static int
+__mt9m114_write_reg_is_consecutive(struct i2c_client *client,
+                                  struct mt9m114_write_ctrl *ctrl,
+                                  const struct misensor_reg *next)
+{
+       if (ctrl->index == 0)
+               return 1;
+
+       return ctrl->buffer.addr + ctrl->index == next->reg;
+}
+
+/*
+ * mt9m114_write_reg_array - Initializes a list of mt9m114 registers
+ * @client: i2c driver client structure
+ * @reglist: list of registers to be written
+ * @poll: completion polling requirement
+ * This function initializes a list of registers. When consecutive addresses
+ * are found in a row on the list, this function creates a buffer and sends
+ * consecutive data in a single i2c_transfer().
+ *
+ * __mt9m114_flush_reg_array, __mt9m114_buf_reg_array() and
+ * __mt9m114_write_reg_is_consecutive() are internal functions to
+ * mt9m114_write_reg_array() and should be not used anywhere else.
+ *
+ */
+static int mt9m114_write_reg_array(struct i2c_client *client,
+                               const struct misensor_reg *reglist,
+                               int poll)
+{
+       const struct misensor_reg *next = reglist;
+       struct mt9m114_write_ctrl ctrl;
+       int err;
+
+       if (poll == PRE_POLLING) {
+               err = mt9m114_wait_state(client, MT9M114_WAIT_STAT_TIMEOUT);
+               if (err)
+                       return err;
+       }
+
+       ctrl.index = 0;
+       for (; next->length != MISENSOR_TOK_TERM; next++) {
+               switch (next->length & MISENSOR_TOK_MASK) {
+               case MISENSOR_TOK_DELAY:
+                       err = __mt9m114_flush_reg_array(client, &ctrl);
+                       if (err)
+                               return err;
+                       msleep(next->val);
+                       break;
+               case MISENSOR_TOK_RMW:
+                       err = __mt9m114_flush_reg_array(client, &ctrl);
+                       err |= misensor_rmw_reg(client,
+                                               next->length &
+                                                       ~MISENSOR_TOK_RMW,
+                                               next->reg, next->val,
+                                               next->val2);
+                       if (err) {
+                               dev_err(&client->dev, "%s read err. aborted\n",
+                                       __func__);
+                               return -EINVAL;
+                       }
+                       break;
+               default:
+                       /*
+                        * If next address is not consecutive, data needs to be
+                        * flushed before proceed.
+                        */
+                       if (!__mt9m114_write_reg_is_consecutive(client, &ctrl,
+                                                               next)) {
+                               err = __mt9m114_flush_reg_array(client, &ctrl);
+                               if (err)
+                                       return err;
+                       }
+                       err = __mt9m114_buf_reg_array(client, &ctrl, next);
+                       if (err) {
+                               v4l2_err(client, "%s: write error, aborted\n",
+                                        __func__);
+                               return err;
+                       }
+                       break;
+               }
+       }
+
+       err = __mt9m114_flush_reg_array(client, &ctrl);
+       if (err)
+               return err;
+
+       if (poll == POST_POLLING)
+               return mt9m114_wait_state(client, MT9M114_WAIT_STAT_TIMEOUT);
+
+       return 0;
+}
+
+static int mt9m114_wait_state(struct i2c_client *client, int timeout)
+{
+       int ret;
+       unsigned int val;
+
+       while (timeout-- > 0) {
+               ret = mt9m114_read_reg(client, MISENSOR_16BIT, 0x0080, &val);
+               if (ret)
+                       return ret;
+               if ((val & 0x2) == 0)
+                       return 0;
+               msleep(20);
+       }
+
+       return -EINVAL;
+
+}
+
+static int mt9m114_set_suspend(struct v4l2_subdev *sd)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       return mt9m114_write_reg_array(client,
+                       mt9m114_standby_reg, POST_POLLING);
+}
+
+static int mt9m114_init_common(struct v4l2_subdev *sd)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       return mt9m114_write_reg_array(client, mt9m114_common, PRE_POLLING);
+}
+
+static int power_ctrl(struct v4l2_subdev *sd, bool flag)
+{
+       int ret;
+       struct mt9m114_device *dev = to_mt9m114_sensor(sd);
+
+       if (!dev || !dev->platform_data)
+               return -ENODEV;
+
+       /* Non-gmin platforms use the legacy callback */
+       if (dev->platform_data->power_ctrl)
+               return dev->platform_data->power_ctrl(sd, flag);
+
+       if (flag) {
+               ret = dev->platform_data->v2p8_ctrl(sd, 1);
+               if (ret == 0) {
+                       ret = dev->platform_data->v1p8_ctrl(sd, 1);
+                       if (ret)
+                               ret = dev->platform_data->v2p8_ctrl(sd, 0);
+               }
+       } else {
+               ret = dev->platform_data->v2p8_ctrl(sd, 0);
+               ret = dev->platform_data->v1p8_ctrl(sd, 0);
+       }
+       return ret;
+}
+
+static int gpio_ctrl(struct v4l2_subdev *sd, bool flag)
+{
+       int ret;
+       struct mt9m114_device *dev = to_mt9m114_sensor(sd);
+
+       if (!dev || !dev->platform_data)
+               return -ENODEV;
+
+       /* Non-gmin platforms use the legacy callback */
+       if (dev->platform_data->gpio_ctrl)
+               return dev->platform_data->gpio_ctrl(sd, flag);
+
+       /* Note: current modules wire only one GPIO signal (RESET#),
+        * but the schematic wires up two to the connector.  BIOS
+        * versions have been unfortunately inconsistent with which
+        * ACPI index RESET# is on, so hit both */
+
+       if (flag) {
+               ret = dev->platform_data->gpio0_ctrl(sd, 0);
+               ret = dev->platform_data->gpio1_ctrl(sd, 0);
+               msleep(60);
+               ret |= dev->platform_data->gpio0_ctrl(sd, 1);
+               ret |= dev->platform_data->gpio1_ctrl(sd, 1);
+       } else {
+               ret = dev->platform_data->gpio0_ctrl(sd, 0);
+               ret = dev->platform_data->gpio1_ctrl(sd, 0);
+       }
+       return ret;
+}
+
+static int power_up(struct v4l2_subdev *sd)
+{
+       struct mt9m114_device *dev = to_mt9m114_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret;
+
+       if (NULL == dev->platform_data) {
+               dev_err(&client->dev, "no camera_sensor_platform_data");
+               return -ENODEV;
+       }
+
+       /* power control */
+       ret = power_ctrl(sd, 1);
+       if (ret)
+               goto fail_power;
+
+       /* flis clock control */
+       ret = dev->platform_data->flisclk_ctrl(sd, 1);
+       if (ret)
+               goto fail_clk;
+
+       /* gpio ctrl */
+       ret = gpio_ctrl(sd, 1);
+       if (ret)
+               dev_err(&client->dev, "gpio failed 1\n");
+       /*
+        * according to DS, 44ms is needed between power up and first i2c
+        * commend
+        */
+       msleep(50);
+
+       return 0;
+
+fail_clk:
+       dev->platform_data->flisclk_ctrl(sd, 0);
+fail_power:
+       power_ctrl(sd, 0);
+       dev_err(&client->dev, "sensor power-up failed\n");
+
+       return ret;
+}
+
+static int power_down(struct v4l2_subdev *sd)
+{
+       struct mt9m114_device *dev = to_mt9m114_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret;
+
+       if (NULL == dev->platform_data) {
+               dev_err(&client->dev, "no camera_sensor_platform_data");
+               return -ENODEV;
+       }
+
+       ret = dev->platform_data->flisclk_ctrl(sd, 0);
+       if (ret)
+               dev_err(&client->dev, "flisclk failed\n");
+
+       /* gpio ctrl */
+       ret = gpio_ctrl(sd, 0);
+       if (ret)
+               dev_err(&client->dev, "gpio failed 1\n");
+
+       /* power control */
+       ret = power_ctrl(sd, 0);
+       if (ret)
+               dev_err(&client->dev, "vprog failed.\n");
+
+       /*according to DS, 20ms is needed after power down*/
+       msleep(20);
+
+       return ret;
+}
+
+static int mt9m114_s_power(struct v4l2_subdev *sd, int power)
+{
+       if (power == 0)
+               return power_down(sd);
+       else {
+               if (power_up(sd))
+                       return -EINVAL;
+
+               return mt9m114_init_common(sd);
+       }
+}
+
+/*
+ * distance - calculate the distance
+ * @res: resolution
+ * @w: width
+ * @h: height
+ *
+ * Get the gap between resolution and w/h.
+ * res->width/height smaller than w/h wouldn't be considered.
+ * Returns the value of gap or -1 if fail.
+ */
+#define LARGEST_ALLOWED_RATIO_MISMATCH 600
+static int distance(struct mt9m114_res_struct const *res, u32 w, u32 h)
+{
+       unsigned int w_ratio;
+       unsigned int h_ratio;
+       int match;
+
+       if (w == 0)
+               return -1;
+       w_ratio = (res->width << 13) / w;
+       if (h == 0)
+               return -1;
+       h_ratio = (res->height << 13) / h;
+       if (h_ratio == 0)
+               return -1;
+       match   = abs(((w_ratio << 13) / h_ratio) - 8192);
+
+       if ((w_ratio < 8192) || (h_ratio < 8192) ||
+           (match > LARGEST_ALLOWED_RATIO_MISMATCH))
+               return -1;
+
+       return w_ratio + h_ratio;
+}
+
+/* Return the nearest higher resolution index */
+static int nearest_resolution_index(int w, int h)
+{
+       int i;
+       int idx = -1;
+       int dist;
+       int min_dist = INT_MAX;
+       const struct mt9m114_res_struct *tmp_res = NULL;
+
+       for (i = 0; i < ARRAY_SIZE(mt9m114_res); i++) {
+               tmp_res = &mt9m114_res[i];
+               dist = distance(tmp_res, w, h);
+               if (dist == -1)
+                       continue;
+               if (dist < min_dist) {
+                       min_dist = dist;
+                       idx = i;
+               }
+       }
+
+       return idx;
+}
+
+static int mt9m114_try_res(u32 *w, u32 *h)
+{
+       int idx = 0;
+
+       if ((*w > MT9M114_RES_960P_SIZE_H)
+               || (*h > MT9M114_RES_960P_SIZE_V)) {
+               *w = MT9M114_RES_960P_SIZE_H;
+               *h = MT9M114_RES_960P_SIZE_V;
+       } else {
+               idx = nearest_resolution_index(*w, *h);
+
+               /*
+                * nearest_resolution_index() doesn't return smaller
+                *  resolutions. If it fails, it means the requested
+                *  resolution is higher than wecan support. Fallback
+                *  to highest possible resolution in this case.
+                */
+               if (idx == -1)
+                       idx = ARRAY_SIZE(mt9m114_res) - 1;
+
+               *w = mt9m114_res[idx].width;
+               *h = mt9m114_res[idx].height;
+       }
+
+       return 0;
+}
+
+static struct mt9m114_res_struct *mt9m114_to_res(u32 w, u32 h)
+{
+       int  index;
+
+       for (index = 0; index < N_RES; index++) {
+               if ((mt9m114_res[index].width == w) &&
+                   (mt9m114_res[index].height == h))
+                       break;
+       }
+
+       /* No mode found */
+       if (index >= N_RES)
+               return NULL;
+
+       return &mt9m114_res[index];
+}
+
+static int mt9m114_res2size(struct v4l2_subdev *sd, int *h_size, int *v_size)
+{
+       struct mt9m114_device *dev = to_mt9m114_sensor(sd);
+       unsigned short hsize;
+       unsigned short vsize;
+
+       switch (dev->res) {
+       case MT9M114_RES_736P:
+               hsize = MT9M114_RES_736P_SIZE_H;
+               vsize = MT9M114_RES_736P_SIZE_V;
+               break;
+       case MT9M114_RES_864P:
+               hsize = MT9M114_RES_864P_SIZE_H;
+               vsize = MT9M114_RES_864P_SIZE_V;
+               break;
+       case MT9M114_RES_960P:
+               hsize = MT9M114_RES_960P_SIZE_H;
+               vsize = MT9M114_RES_960P_SIZE_V;
+               break;
+       default:
+               v4l2_err(sd, "%s: Resolution 0x%08x unknown\n", __func__,
+                        dev->res);
+               return -EINVAL;
+       }
+
+       if (h_size != NULL)
+               *h_size = hsize;
+       if (v_size != NULL)
+               *v_size = vsize;
+
+       return 0;
+}
+
+static int mt9m114_get_intg_factor(struct i2c_client *client,
+                               struct camera_mipi_info *info,
+                               const struct mt9m114_res_struct *res)
+{
+       struct atomisp_sensor_mode_data *buf = &info->data;
+       u32 reg_val;
+       int ret;
+
+       if (info == NULL)
+               return -EINVAL;
+
+       ret =  mt9m114_read_reg(client, MISENSOR_32BIT,
+                                       REG_PIXEL_CLK, &reg_val);
+       if (ret)
+               return ret;
+       buf->vt_pix_clk_freq_mhz = reg_val;
+
+       /* get integration time */
+       buf->coarse_integration_time_min = MT9M114_COARSE_INTG_TIME_MIN;
+       buf->coarse_integration_time_max_margin =
+                                       MT9M114_COARSE_INTG_TIME_MAX_MARGIN;
+
+       buf->fine_integration_time_min = MT9M114_FINE_INTG_TIME_MIN;
+       buf->fine_integration_time_max_margin =
+                                       MT9M114_FINE_INTG_TIME_MAX_MARGIN;
+
+       buf->fine_integration_time_def = MT9M114_FINE_INTG_TIME_MIN;
+
+       buf->frame_length_lines = res->lines_per_frame;
+       buf->line_length_pck = res->pixels_per_line;
+       buf->read_mode = res->bin_mode;
+
+       /* get the cropping and output resolution to ISP for this mode. */
+       ret =  mt9m114_read_reg(client, MISENSOR_16BIT,
+                                       REG_H_START, &reg_val);
+       if (ret)
+               return ret;
+       buf->crop_horizontal_start = reg_val;
+
+       ret =  mt9m114_read_reg(client, MISENSOR_16BIT,
+                                       REG_V_START, &reg_val);
+       if (ret)
+               return ret;
+       buf->crop_vertical_start = reg_val;
+
+       ret = mt9m114_read_reg(client, MISENSOR_16BIT,
+                                       REG_H_END, &reg_val);
+       if (ret)
+               return ret;
+       buf->crop_horizontal_end = reg_val;
+
+       ret = mt9m114_read_reg(client, MISENSOR_16BIT,
+                                       REG_V_END, &reg_val);
+       if (ret)
+               return ret;
+       buf->crop_vertical_end = reg_val;
+
+       ret = mt9m114_read_reg(client, MISENSOR_16BIT,
+                                       REG_WIDTH, &reg_val);
+       if (ret)
+               return ret;
+       buf->output_width = reg_val;
+
+       ret = mt9m114_read_reg(client, MISENSOR_16BIT,
+                                       REG_HEIGHT, &reg_val);
+       if (ret)
+               return ret;
+       buf->output_height = reg_val;
+
+       ret = mt9m114_read_reg(client, MISENSOR_16BIT,
+                                       REG_TIMING_HTS, &reg_val);
+       if (ret)
+               return ret;
+       buf->line_length_pck = reg_val;
+
+       ret = mt9m114_read_reg(client, MISENSOR_16BIT,
+                                       REG_TIMING_VTS, &reg_val);
+       if (ret)
+               return ret;
+       buf->frame_length_lines = reg_val;
+
+       buf->binning_factor_x = res->bin_factor_x ?
+                                       res->bin_factor_x : 1;
+       buf->binning_factor_y = res->bin_factor_y ?
+                                       res->bin_factor_y : 1;
+       return 0;
+}
+
+static int mt9m114_get_fmt(struct v4l2_subdev *sd,
+                               struct v4l2_subdev_pad_config *cfg,
+                               struct v4l2_subdev_format *format)
+{
+       struct v4l2_mbus_framefmt *fmt = &format->format;
+       int width, height;
+       int ret;
+       if (format->pad)
+               return -EINVAL;
+       fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
+
+       ret = mt9m114_res2size(sd, &width, &height);
+       if (ret)
+               return ret;
+       fmt->width = width;
+       fmt->height = height;
+
+       return 0;
+}
+
+static int mt9m114_set_fmt(struct v4l2_subdev *sd,
+                          struct v4l2_subdev_pad_config *cfg,
+                          struct v4l2_subdev_format *format)
+{
+       struct v4l2_mbus_framefmt *fmt = &format->format;
+       struct i2c_client *c = v4l2_get_subdevdata(sd);
+       struct mt9m114_device *dev = to_mt9m114_sensor(sd);
+       struct mt9m114_res_struct *res_index;
+       u32 width = fmt->width;
+       u32 height = fmt->height;
+       struct camera_mipi_info *mt9m114_info = NULL;
+
+       int ret;
+       if (format->pad)
+               return -EINVAL;
+       dev->streamon = 0;
+       dev->first_exp = MT9M114_DEFAULT_FIRST_EXP;
+
+       mt9m114_info = v4l2_get_subdev_hostdata(sd);
+       if (mt9m114_info == NULL)
+               return -EINVAL;
+
+       mt9m114_try_res(&width, &height);
+       if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+               cfg->try_fmt = *fmt;
+               return 0;
+       }
+       res_index = mt9m114_to_res(width, height);
+
+       /* Sanity check */
+       if (unlikely(!res_index)) {
+               WARN_ON(1);
+               return -EINVAL;
+       }
+
+       switch (res_index->res) {
+       case MT9M114_RES_736P:
+               ret = mt9m114_write_reg_array(c, mt9m114_736P_init, NO_POLLING);
+               ret += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE,
+                               MISENSOR_R_MODE_MASK, MISENSOR_NORMAL_SET);
+               break;
+       case MT9M114_RES_864P:
+               ret = mt9m114_write_reg_array(c, mt9m114_864P_init, NO_POLLING);
+               ret += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE,
+                               MISENSOR_R_MODE_MASK, MISENSOR_NORMAL_SET);
+               break;
+       case MT9M114_RES_960P:
+               ret = mt9m114_write_reg_array(c, mt9m114_976P_init, NO_POLLING);
+               /* set sensor read_mode to Normal */
+               ret += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE,
+                               MISENSOR_R_MODE_MASK, MISENSOR_NORMAL_SET);
+               break;
+       default:
+               v4l2_err(sd, "set resolution: %d failed!\n", res_index->res);
+               return -EINVAL;
+       }
+
+       if (ret)
+               return -EINVAL;
+
+       ret = mt9m114_write_reg_array(c, mt9m114_chgstat_reg, POST_POLLING);
+       if (ret < 0)
+               return ret;
+
+       if (mt9m114_set_suspend(sd))
+               return -EINVAL;
+
+       if (dev->res != res_index->res) {
+               int index;
+
+               /* Switch to different size */
+               if (width <= 640) {
+                       dev->nctx = 0x00; /* Set for context A */
+               } else {
+                       /*
+                        * Context B is used for resolutions larger than 640x480
+                        * Using YUV for Context B.
+                        */
+                       dev->nctx = 0x01; /* set for context B */
+               }
+
+               /*
+                * Marked current sensor res as being "used"
+                *
+                * REVISIT: We don't need to use an "used" field on each mode
+                * list entry to know which mode is selected. If this
+                * information is really necessary, how about to use a single
+                * variable on sensor dev struct?
+                */
+               for (index = 0; index < N_RES; index++) {
+                       if ((width == mt9m114_res[index].width) &&
+                           (height == mt9m114_res[index].height)) {
+                               mt9m114_res[index].used = true;
+                               continue;
+                       }
+                       mt9m114_res[index].used = false;
+               }
+       }
+       ret = mt9m114_get_intg_factor(c, mt9m114_info,
+                                       &mt9m114_res[res_index->res]);
+       if (ret) {
+               dev_err(&c->dev, "failed to get integration_factor\n");
+               return -EINVAL;
+       }
+       /*
+        * mt9m114 - we don't poll for context switch
+        * because it does not happen with streaming disabled.
+        */
+       dev->res = res_index->res;
+
+       fmt->width = width;
+       fmt->height = height;
+       fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
+       return 0;
+}
+
+/* TODO: Update to SOC functions, remove exposure and gain */
+static int mt9m114_g_focal(struct v4l2_subdev *sd, s32 *val)
+{
+       *val = (MT9M114_FOCAL_LENGTH_NUM << 16) | MT9M114_FOCAL_LENGTH_DEM;
+       return 0;
+}
+
+static int mt9m114_g_fnumber(struct v4l2_subdev *sd, s32 *val)
+{
+       /*const f number for mt9m114*/
+       *val = (MT9M114_F_NUMBER_DEFAULT_NUM << 16) | MT9M114_F_NUMBER_DEM;
+       return 0;
+}
+
+static int mt9m114_g_fnumber_range(struct v4l2_subdev *sd, s32 *val)
+{
+       *val = (MT9M114_F_NUMBER_DEFAULT_NUM << 24) |
+               (MT9M114_F_NUMBER_DEM << 16) |
+               (MT9M114_F_NUMBER_DEFAULT_NUM << 8) | MT9M114_F_NUMBER_DEM;
+       return 0;
+}
+
+/* Horizontal flip the image. */
+static int mt9m114_g_hflip(struct v4l2_subdev *sd, s32 *val)
+{
+       struct i2c_client *c = v4l2_get_subdevdata(sd);
+       int ret;
+       u32 data;
+       ret = mt9m114_read_reg(c, MISENSOR_16BIT,
+                       (u32)MISENSOR_READ_MODE, &data);
+       if (ret)
+               return ret;
+       *val = !!(data & MISENSOR_HFLIP_MASK);
+
+       return 0;
+}
+
+static int mt9m114_g_vflip(struct v4l2_subdev *sd, s32 *val)
+{
+       struct i2c_client *c = v4l2_get_subdevdata(sd);
+       int ret;
+       u32 data;
+
+       ret = mt9m114_read_reg(c, MISENSOR_16BIT,
+                       (u32)MISENSOR_READ_MODE, &data);
+       if (ret)
+               return ret;
+       *val = !!(data & MISENSOR_VFLIP_MASK);
+
+       return 0;
+}
+
+static long mt9m114_s_exposure(struct v4l2_subdev *sd,
+                              struct atomisp_exposure *exposure)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct mt9m114_device *dev = to_mt9m114_sensor(sd);
+       int ret = 0;
+       unsigned int coarse_integration = 0;
+       unsigned int fine_integration = 0;
+       unsigned int FLines = 0;
+       unsigned int FrameLengthLines = 0; /* ExposureTime.FrameLengthLines; */
+       unsigned int AnalogGain, DigitalGain;
+       u32 AnalogGainToWrite = 0;
+       u16 exposure_local[3];
+
+       dev_dbg(&client->dev, "%s(0x%X 0x%X 0x%X)\n", __func__,
+                   exposure->integration_time[0], exposure->gain[0],
+                   exposure->gain[1]);
+
+       coarse_integration = exposure->integration_time[0];
+       /* fine_integration = ExposureTime.FineIntegrationTime; */
+       /* FrameLengthLines = ExposureTime.FrameLengthLines; */
+       FLines = mt9m114_res[dev->res].lines_per_frame;
+       AnalogGain = exposure->gain[0];
+       DigitalGain = exposure->gain[1];
+       if (!dev->streamon) {
+               /*Save the first exposure values while stream is off*/
+               dev->first_exp = coarse_integration;
+               dev->first_gain = AnalogGain;
+               dev->first_diggain = DigitalGain;
+       }
+       /* DigitalGain = 0x400 * (((u16) DigitalGain) >> 8) +
+       ((unsigned int)(0x400 * (((u16) DigitalGain) & 0xFF)) >>8); */
+
+       /* set frame length */
+       if (FLines < coarse_integration + 6)
+               FLines = coarse_integration + 6;
+       if (FLines < FrameLengthLines)
+               FLines = FrameLengthLines;
+       ret = mt9m114_write_reg(client, MISENSOR_16BIT, 0x300A, FLines);
+       if (ret) {
+               v4l2_err(client, "%s: fail to set FLines\n", __func__);
+               return -EINVAL;
+       }
+
+       /* set coarse/fine integration */
+       exposure_local[0] = REG_EXPO_COARSE;
+       exposure_local[1] = (u16)coarse_integration;
+       exposure_local[2] = (u16)fine_integration;
+       /* 3A provide real exposure time.
+               should not translate to any value here. */
+       ret = mt9m114_write_reg(client, MISENSOR_16BIT,
+                       REG_EXPO_COARSE, (u16)(coarse_integration));
+       if (ret) {
+               v4l2_err(client, "%s: fail to set exposure time\n", __func__);
+               return -EINVAL;
+       }
+
+       /*
+       // set analog/digital gain
+       switch(AnalogGain)
+       {
+       case 0:
+         AnalogGainToWrite = 0x0;
+         break;
+       case 1:
+         AnalogGainToWrite = 0x20;
+         break;
+       case 2:
+         AnalogGainToWrite = 0x60;
+         break;
+       case 4:
+         AnalogGainToWrite = 0xA0;
+         break;
+       case 8:
+         AnalogGainToWrite = 0xE0;
+         break;
+       default:
+         AnalogGainToWrite = 0x20;
+         break;
+       }
+       */
+       if (DigitalGain >= 16 || DigitalGain <= 1)
+               DigitalGain = 1;
+       /* AnalogGainToWrite =
+               (u16)((DigitalGain << 12) | AnalogGainToWrite); */
+       AnalogGainToWrite = (u16)((DigitalGain << 12) | (u16)AnalogGain);
+       ret = mt9m114_write_reg(client, MISENSOR_16BIT,
+                                       REG_GAIN, AnalogGainToWrite);
+       if (ret) {
+               v4l2_err(client, "%s: fail to set AnalogGainToWrite\n",
+                       __func__);
+               return -EINVAL;
+       }
+
+       return ret;
+}
+
+static long mt9m114_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+
+       switch (cmd) {
+       case ATOMISP_IOC_S_EXPOSURE:
+               return mt9m114_s_exposure(sd, arg);
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* This returns the exposure time being used. This should only be used
+   for filling in EXIF data, not for actual image processing. */
+static int mt9m114_g_exposure(struct v4l2_subdev *sd, s32 *value)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       u32 coarse;
+       int ret;
+
+       /* the fine integration time is currently not calculated */
+       ret = mt9m114_read_reg(client, MISENSOR_16BIT,
+                              REG_EXPO_COARSE, &coarse);
+       if (ret)
+               return ret;
+
+       *value = coarse;
+       return 0;
+}
+#ifndef CSS15
+/*
+ * This function will return the sensor supported max exposure zone number.
+ * the sensor which supports max exposure zone number is 1.
+ */
+static int mt9m114_g_exposure_zone_num(struct v4l2_subdev *sd, s32 *val)
+{
+       *val = 1;
+
+       return 0;
+}
+
+/*
+ * set exposure metering, average/center_weighted/spot/matrix.
+ */
+static int mt9m114_s_exposure_metering(struct v4l2_subdev *sd, s32 val)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret;
+
+       switch (val) {
+       case V4L2_EXPOSURE_METERING_SPOT:
+               ret = mt9m114_write_reg_array(client, mt9m114_exp_average,
+                                               NO_POLLING);
+               if (ret) {
+                       dev_err(&client->dev, "write exp_average reg err.\n");
+                       return ret;
+               }
+               break;
+       case V4L2_EXPOSURE_METERING_CENTER_WEIGHTED:
+       default:
+               ret = mt9m114_write_reg_array(client, mt9m114_exp_center,
+                                               NO_POLLING);
+               if (ret) {
+                       dev_err(&client->dev, "write exp_default reg err");
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * This function is for touch exposure feature.
+ */
+static int mt9m114_s_exposure_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 misensor_reg exp_reg;
+       int width, height;
+       int grid_width, grid_height;
+       int grid_left, grid_top, grid_right, grid_bottom;
+       int win_left, win_top, win_right, win_bottom;
+       int i, j;
+       int ret;
+
+       if (sel->which != V4L2_SUBDEV_FORMAT_TRY &&
+           sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+               return -EINVAL;
+
+       grid_left = sel->r.left;
+       grid_top = sel->r.top;
+       grid_right = sel->r.left + sel->r.width - 1;
+       grid_bottom = sel->r.top + sel->r.height - 1;
+
+       ret = mt9m114_res2size(sd, &width, &height);
+       if (ret)
+               return ret;
+
+       grid_width = width / 5;
+       grid_height = height / 5;
+
+       if (grid_width && grid_height) {
+               win_left = grid_left / grid_width;
+               win_top = grid_top / grid_height;
+               win_right = grid_right / grid_width;
+               win_bottom = grid_bottom / grid_height;
+       } else {
+               dev_err(&client->dev, "Incorrect exp grid.\n");
+               return -EINVAL;
+       }
+
+       win_left   = clamp_t(int, win_left, 0, 4);
+       win_top    = clamp_t(int, win_top, 0, 4);
+       win_right  = clamp_t(int, win_right, 0, 4);
+       win_bottom = clamp_t(int, win_bottom, 0, 4);
+
+       ret = mt9m114_write_reg_array(client, mt9m114_exp_average, NO_POLLING);
+       if (ret) {
+               dev_err(&client->dev, "write exp_average reg err.\n");
+               return ret;
+       }
+
+       for (i = win_top; i <= win_bottom; i++) {
+               for (j = win_left; j <= win_right; j++) {
+                       exp_reg = mt9m114_exp_win[i][j];
+
+                       ret = mt9m114_write_reg(client, exp_reg.length,
+                                               exp_reg.reg, exp_reg.val);
+                       if (ret) {
+                               dev_err(&client->dev, "write exp_reg err.\n");
+                               return ret;
+                       }
+               }
+       }
+
+       return 0;
+}
+#endif
+
+static int mt9m114_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val)
+{
+       struct mt9m114_device *dev = to_mt9m114_sensor(sd);
+
+       *val = mt9m114_res[dev->res].bin_factor_x;
+
+       return 0;
+}
+
+static int mt9m114_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val)
+{
+       struct mt9m114_device *dev = to_mt9m114_sensor(sd);
+
+       *val = mt9m114_res[dev->res].bin_factor_y;
+
+       return 0;
+}
+
+static int mt9m114_s_ev(struct v4l2_subdev *sd, s32 val)
+{
+       struct i2c_client *c = v4l2_get_subdevdata(sd);
+       s32 luma = 0x37;
+       int err;
+
+       /* EV value only support -2 to 2
+        * 0: 0x37, 1:0x47, 2:0x57, -1:0x27, -2:0x17
+        */
+       if (val < -2 || val > 2)
+               return -EINVAL;
+       luma += 0x10 * val;
+       dev_dbg(&c->dev, "%s val:%d luma:0x%x\n", __func__, val, luma);
+       err = mt9m114_write_reg(c, MISENSOR_16BIT, 0x098E, 0xC87A);
+       if (err) {
+               dev_err(&c->dev, "%s logic addr access error\n", __func__);
+               return err;
+       }
+       err = mt9m114_write_reg(c, MISENSOR_8BIT, 0xC87A, (u32)luma);
+       if (err) {
+               dev_err(&c->dev, "%s write target_average_luma failed\n",
+                       __func__);
+               return err;
+       }
+       udelay(10);
+
+       return 0;
+}
+
+static int mt9m114_g_ev(struct v4l2_subdev *sd, s32 *val)
+{
+       struct i2c_client *c = v4l2_get_subdevdata(sd);
+       int err;
+       u32 luma;
+
+       err = mt9m114_write_reg(c, MISENSOR_16BIT, 0x098E, 0xC87A);
+       if (err) {
+               dev_err(&c->dev, "%s logic addr access error\n", __func__);
+               return err;
+       }
+       err = mt9m114_read_reg(c, MISENSOR_8BIT, 0xC87A, &luma);
+       if (err) {
+               dev_err(&c->dev, "%s read target_average_luma failed\n",
+                       __func__);
+               return err;
+       }
+       luma -= 0x17;
+       luma /= 0x10;
+       *val = (s32)luma - 2;
+       dev_dbg(&c->dev, "%s val:%d\n", __func__, *val);
+
+       return 0;
+}
+
+/* Fake interface
+ * mt9m114 now can not support 3a_lock
+*/
+static int mt9m114_s_3a_lock(struct v4l2_subdev *sd, s32 val)
+{
+       aaalock = val;
+       return 0;
+}
+
+static int mt9m114_g_3a_lock(struct v4l2_subdev *sd, s32 *val)
+{
+       if (aaalock)
+               return V4L2_LOCK_EXPOSURE | V4L2_LOCK_WHITE_BALANCE
+                       | V4L2_LOCK_FOCUS;
+       return 0;
+}
+
+static int mt9m114_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct mt9m114_device *dev =
+           container_of(ctrl->handler, struct mt9m114_device, ctrl_handler);
+       struct i2c_client *client = v4l2_get_subdevdata(&dev->sd);
+       int ret = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_VFLIP:
+               dev_dbg(&client->dev, "%s: CID_VFLIP:%d.\n",
+                       __func__, ctrl->val);
+               ret = mt9m114_t_vflip(&dev->sd, ctrl->val);
+               break;
+       case V4L2_CID_HFLIP:
+               dev_dbg(&client->dev, "%s: CID_HFLIP:%d.\n",
+                       __func__, ctrl->val);
+               ret = mt9m114_t_hflip(&dev->sd, ctrl->val);
+               break;
+#ifndef CSS15
+       case V4L2_CID_EXPOSURE_METERING:
+               ret = mt9m114_s_exposure_metering(&dev->sd, ctrl->val);
+               break;
+#endif
+       case V4L2_CID_EXPOSURE:
+               ret = mt9m114_s_ev(&dev->sd, ctrl->val);
+               break;
+       case V4L2_CID_3A_LOCK:
+               ret = mt9m114_s_3a_lock(&dev->sd, ctrl->val);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+       return ret;
+}
+
+static int mt9m114_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct mt9m114_device *dev =
+           container_of(ctrl->handler, struct mt9m114_device, ctrl_handler);
+       int ret = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_VFLIP:
+               ret = mt9m114_g_vflip(&dev->sd, &ctrl->val);
+               break;
+       case V4L2_CID_HFLIP:
+               ret = mt9m114_g_hflip(&dev->sd, &ctrl->val);
+               break;
+       case V4L2_CID_FOCAL_ABSOLUTE:
+               ret = mt9m114_g_focal(&dev->sd, &ctrl->val);
+               break;
+       case V4L2_CID_FNUMBER_ABSOLUTE:
+               ret = mt9m114_g_fnumber(&dev->sd, &ctrl->val);
+               break;
+       case V4L2_CID_FNUMBER_RANGE:
+               ret = mt9m114_g_fnumber_range(&dev->sd, &ctrl->val);
+               break;
+       case V4L2_CID_EXPOSURE_ABSOLUTE:
+               ret = mt9m114_g_exposure(&dev->sd, &ctrl->val);
+               break;
+#ifndef CSS15
+       case V4L2_CID_EXPOSURE_ZONE_NUM:
+               ret = mt9m114_g_exposure_zone_num(&dev->sd, &ctrl->val);
+               break;
+#endif
+       case V4L2_CID_BIN_FACTOR_HORZ:
+               ret = mt9m114_g_bin_factor_x(&dev->sd, &ctrl->val);
+               break;
+       case V4L2_CID_BIN_FACTOR_VERT:
+               ret = mt9m114_g_bin_factor_y(&dev->sd, &ctrl->val);
+               break;
+       case V4L2_CID_EXPOSURE:
+               ret = mt9m114_g_ev(&dev->sd, &ctrl->val);
+               break;
+       case V4L2_CID_3A_LOCK:
+               ret = mt9m114_g_3a_lock(&dev->sd, &ctrl->val);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static const struct v4l2_ctrl_ops ctrl_ops = {
+       .s_ctrl = mt9m114_s_ctrl,
+       .g_volatile_ctrl = mt9m114_g_volatile_ctrl
+};
+
+static struct v4l2_ctrl_config mt9m114_controls[] = {
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_VFLIP,
+        .name = "Image v-Flip",
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .min = 0,
+        .max = 1,
+        .step = 1,
+        .def = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_HFLIP,
+        .name = "Image h-Flip",
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .min = 0,
+        .max = 1,
+        .step = 1,
+        .def = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_FOCAL_ABSOLUTE,
+        .name = "focal length",
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .min = MT9M114_FOCAL_LENGTH_DEFAULT,
+        .max = MT9M114_FOCAL_LENGTH_DEFAULT,
+        .step = 1,
+        .def = MT9M114_FOCAL_LENGTH_DEFAULT,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_FNUMBER_ABSOLUTE,
+        .name = "f-number",
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .min = MT9M114_F_NUMBER_DEFAULT,
+        .max = MT9M114_F_NUMBER_DEFAULT,
+        .step = 1,
+        .def = MT9M114_F_NUMBER_DEFAULT,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_FNUMBER_RANGE,
+        .name = "f-number range",
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .min = MT9M114_F_NUMBER_RANGE,
+        .max = MT9M114_F_NUMBER_RANGE,
+        .step = 1,
+        .def = MT9M114_F_NUMBER_RANGE,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_EXPOSURE_ABSOLUTE,
+        .name = "exposure",
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .min = 0,
+        .max = 0xffff,
+        .step = 1,
+        .def = 0,
+        .flags = 0,
+        },
+#ifndef CSS15
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_EXPOSURE_ZONE_NUM,
+        .name = "one-time exposure zone number",
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .min = 0,
+        .max = 0xffff,
+        .step = 1,
+        .def = 0,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_EXPOSURE_METERING,
+        .name = "metering",
+        .type = V4L2_CTRL_TYPE_MENU,
+        .min = 0,
+        .max = 3,
+        .step = 0,
+        .def = 1,
+        .flags = 0,
+        },
+#endif
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_BIN_FACTOR_HORZ,
+        .name = "horizontal binning factor",
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .min = 0,
+        .max = MT9M114_BIN_FACTOR_MAX,
+        .step = 1,
+        .def = 0,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_BIN_FACTOR_VERT,
+        .name = "vertical binning factor",
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .min = 0,
+        .max = MT9M114_BIN_FACTOR_MAX,
+        .step = 1,
+        .def = 0,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_EXPOSURE,
+        .name = "exposure biasx",
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .min = -2,
+        .max = 2,
+        .step = 1,
+        .def = 0,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_3A_LOCK,
+        .name = "3a lock",
+        .type = V4L2_CTRL_TYPE_BITMASK,
+        .min = 0,
+        .max = V4L2_LOCK_EXPOSURE | V4L2_LOCK_WHITE_BALANCE | V4L2_LOCK_FOCUS,
+        .step = 1,
+        .def = 0,
+        .flags = 0,
+        },
+};
+
+static int mt9m114_detect(struct mt9m114_device *dev, struct i2c_client *client)
+{
+       struct i2c_adapter *adapter = client->adapter;
+       u32 retvalue;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
+               dev_err(&client->dev, "%s: i2c error", __func__);
+               return -ENODEV;
+       }
+       mt9m114_read_reg(client, MISENSOR_16BIT, (u32)MT9M114_PID, &retvalue);
+       dev->real_model_id = retvalue;
+
+       if (retvalue != MT9M114_MOD_ID) {
+               dev_err(&client->dev, "%s: failed: client->addr = %x\n",
+                       __func__, client->addr);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static int
+mt9m114_s_config(struct v4l2_subdev *sd, int irq, void *platform_data)
+{
+       struct mt9m114_device *dev = to_mt9m114_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret;
+
+       if (NULL == platform_data)
+               return -ENODEV;
+
+       dev->platform_data =
+           (struct camera_sensor_platform_data *)platform_data;
+
+       if (dev->platform_data->platform_init) {
+               ret = dev->platform_data->platform_init(client);
+               if (ret) {
+                       v4l2_err(client, "mt9m114 platform init err\n");
+                       return ret;
+               }
+       }
+       ret = power_up(sd);
+       if (ret) {
+               v4l2_err(client, "mt9m114 power-up err");
+               return ret;
+       }
+
+       /* config & detect sensor */
+       ret = mt9m114_detect(dev, client);
+       if (ret) {
+               v4l2_err(client, "mt9m114_detect err s_config.\n");
+               goto fail_detect;
+       }
+
+       ret = dev->platform_data->csi_cfg(sd, 1);
+       if (ret)
+               goto fail_csi_cfg;
+
+       ret = mt9m114_set_suspend(sd);
+       if (ret) {
+               v4l2_err(client, "mt9m114 suspend err");
+               return ret;
+       }
+
+       ret = power_down(sd);
+       if (ret) {
+               v4l2_err(client, "mt9m114 power down err");
+               return ret;
+       }
+
+       return ret;
+
+fail_csi_cfg:
+       dev->platform_data->csi_cfg(sd, 0);
+fail_detect:
+       power_down(sd);
+       dev_err(&client->dev, "sensor power-gating failed\n");
+       return ret;
+}
+
+/* Horizontal flip the image. */
+static int mt9m114_t_hflip(struct v4l2_subdev *sd, int value)
+{
+       struct i2c_client *c = v4l2_get_subdevdata(sd);
+       struct mt9m114_device *dev = to_mt9m114_sensor(sd);
+       int err;
+       /* set for direct mode */
+       err = mt9m114_write_reg(c, MISENSOR_16BIT, 0x098E, 0xC850);
+       if (value) {
+               /* enable H flip ctx A */
+               err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC850, 0x01, 0x01);
+               err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC851, 0x01, 0x01);
+               /* ctx B */
+               err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC888, 0x01, 0x01);
+               err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC889, 0x01, 0x01);
+
+               err += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE,
+                                       MISENSOR_HFLIP_MASK, MISENSOR_FLIP_EN);
+
+               dev->bpat = MT9M114_BPAT_GRGRBGBG;
+       } else {
+               /* disable H flip ctx A */
+               err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC850, 0x01, 0x00);
+               err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC851, 0x01, 0x00);
+               /* ctx B */
+               err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC888, 0x01, 0x00);
+               err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC889, 0x01, 0x00);
+
+               err += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE,
+                                       MISENSOR_HFLIP_MASK, MISENSOR_FLIP_DIS);
+
+               dev->bpat = MT9M114_BPAT_BGBGGRGR;
+       }
+
+       err += mt9m114_write_reg(c, MISENSOR_8BIT, 0x8404, 0x06);
+       udelay(10);
+
+       return !!err;
+}
+
+/* Vertically flip the image */
+static int mt9m114_t_vflip(struct v4l2_subdev *sd, int value)
+{
+       struct i2c_client *c = v4l2_get_subdevdata(sd);
+       int err;
+       /* set for direct mode */
+       err = mt9m114_write_reg(c, MISENSOR_16BIT, 0x098E, 0xC850);
+       if (value >= 1) {
+               /* enable H flip - ctx A */
+               err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC850, 0x02, 0x01);
+               err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC851, 0x02, 0x01);
+               /* ctx B */
+               err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC888, 0x02, 0x01);
+               err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC889, 0x02, 0x01);
+
+               err += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE,
+                                       MISENSOR_VFLIP_MASK, MISENSOR_FLIP_EN);
+       } else {
+               /* disable H flip - ctx A */
+               err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC850, 0x02, 0x00);
+               err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC851, 0x02, 0x00);
+               /* ctx B */
+               err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC888, 0x02, 0x00);
+               err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC889, 0x02, 0x00);
+
+               err += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE,
+                                       MISENSOR_VFLIP_MASK, MISENSOR_FLIP_DIS);
+       }
+
+       err += mt9m114_write_reg(c, MISENSOR_8BIT, 0x8404, 0x06);
+       udelay(10);
+
+       return !!err;
+}
+static int mt9m114_s_parm(struct v4l2_subdev *sd,
+                       struct v4l2_streamparm *param)
+{
+       return 0;
+}
+
+static int mt9m114_g_frame_interval(struct v4l2_subdev *sd,
+                                  struct v4l2_subdev_frame_interval *interval)
+{
+       struct mt9m114_device *dev = to_mt9m114_sensor(sd);
+
+       interval->interval.numerator = 1;
+       interval->interval.denominator = mt9m114_res[dev->res].fps;
+
+       return 0;
+}
+
+static int mt9m114_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       int ret;
+       struct i2c_client *c = v4l2_get_subdevdata(sd);
+       struct mt9m114_device *dev = to_mt9m114_sensor(sd);
+       struct atomisp_exposure exposure;
+
+       if (enable) {
+               ret = mt9m114_write_reg_array(c, mt9m114_chgstat_reg,
+                                       POST_POLLING);
+               if (ret < 0)
+                       return ret;
+
+               if (dev->first_exp > MT9M114_MAX_FIRST_EXP) {
+                       exposure.integration_time[0] = dev->first_exp;
+                       exposure.gain[0] = dev->first_gain;
+                       exposure.gain[1] = dev->first_diggain;
+                       mt9m114_s_exposure(sd, &exposure);
+               }
+               dev->streamon = 1;
+
+       } else {
+               dev->streamon = 0;
+               ret = mt9m114_set_suspend(sd);
+       }
+
+       return ret;
+}
+
+static int mt9m114_enum_mbus_code(struct v4l2_subdev *sd,
+                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_mbus_code_enum *code)
+{
+       if (code->index)
+               return -EINVAL;
+       code->code = MEDIA_BUS_FMT_SGRBG10_1X10;
+
+       return 0;
+}
+
+static int mt9m114_enum_frame_size(struct v4l2_subdev *sd,
+                                  struct v4l2_subdev_pad_config *cfg,
+                                  struct v4l2_subdev_frame_size_enum *fse)
+{
+
+       unsigned int index = fse->index;
+
+       if (index >= N_RES)
+               return -EINVAL;
+
+       fse->min_width = mt9m114_res[index].width;
+       fse->min_height = mt9m114_res[index].height;
+       fse->max_width = mt9m114_res[index].width;
+       fse->max_height = mt9m114_res[index].height;
+
+       return 0;
+}
+
+static int mt9m114_g_skip_frames(struct v4l2_subdev *sd, u32 *frames)
+{
+       int index;
+       struct mt9m114_device *snr = to_mt9m114_sensor(sd);
+
+       if (frames == NULL)
+               return -EINVAL;
+
+       for (index = 0; index < N_RES; index++) {
+               if (mt9m114_res[index].res == snr->res)
+                       break;
+       }
+
+       if (index >= N_RES)
+               return -EINVAL;
+
+       *frames = mt9m114_res[index].skip_frames;
+
+       return 0;
+}
+
+static const struct v4l2_subdev_video_ops mt9m114_video_ops = {
+       .s_parm = mt9m114_s_parm,
+       .s_stream = mt9m114_s_stream,
+       .g_frame_interval = mt9m114_g_frame_interval,
+};
+
+static const struct v4l2_subdev_sensor_ops mt9m114_sensor_ops = {
+       .g_skip_frames  = mt9m114_g_skip_frames,
+};
+
+static const struct v4l2_subdev_core_ops mt9m114_core_ops = {
+       .s_power = mt9m114_s_power,
+       .ioctl = mt9m114_ioctl,
+};
+
+/* REVISIT: Do we need pad operations? */
+static const struct v4l2_subdev_pad_ops mt9m114_pad_ops = {
+       .enum_mbus_code = mt9m114_enum_mbus_code,
+       .enum_frame_size = mt9m114_enum_frame_size,
+       .get_fmt = mt9m114_get_fmt,
+       .set_fmt = mt9m114_set_fmt,
+#ifndef CSS15
+       .set_selection = mt9m114_s_exposure_selection,
+#endif
+};
+
+static const struct v4l2_subdev_ops mt9m114_ops = {
+       .core = &mt9m114_core_ops,
+       .video = &mt9m114_video_ops,
+       .pad = &mt9m114_pad_ops,
+       .sensor = &mt9m114_sensor_ops,
+};
+
+static const struct media_entity_operations mt9m114_entity_ops = {
+       .link_setup = NULL,
+};
+
+static int mt9m114_remove(struct i2c_client *client)
+{
+       struct mt9m114_device *dev;
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+       dev = container_of(sd, struct mt9m114_device, sd);
+       dev->platform_data->csi_cfg(sd, 0);
+       if (dev->platform_data->platform_deinit)
+               dev->platform_data->platform_deinit();
+       v4l2_device_unregister_subdev(sd);
+       media_entity_cleanup(&dev->sd.entity);
+       v4l2_ctrl_handler_free(&dev->ctrl_handler);
+       kfree(dev);
+       return 0;
+}
+
+static int mt9m114_probe(struct i2c_client *client,
+                      const struct i2c_device_id *id)
+{
+       struct mt9m114_device *dev;
+       int ret = 0;
+       unsigned int i;
+       void *pdata;
+
+       /* Setup sensor configuration structure */
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev) {
+               dev_err(&client->dev, "out of memory\n");
+               return -ENOMEM;
+       }
+
+       v4l2_i2c_subdev_init(&dev->sd, client, &mt9m114_ops);
+       pdata = client->dev.platform_data;
+       if (ACPI_COMPANION(&client->dev))
+               pdata = gmin_camera_platform_data(&dev->sd,
+                                                 ATOMISP_INPUT_FORMAT_RAW_10,
+                                                 atomisp_bayer_order_grbg);
+       if (pdata)
+               ret = mt9m114_s_config(&dev->sd, client->irq, pdata);
+       if (!pdata || ret) {
+               v4l2_device_unregister_subdev(&dev->sd);
+               kfree(dev);
+               return ret;
+       }
+
+       ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA);
+       if (ret) {
+               v4l2_device_unregister_subdev(&dev->sd);
+               kfree(dev);
+               /* Coverity CID 298095 - return on error */
+               return ret;
+       }
+
+       /*TODO add format code here*/
+       dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+       dev->pad.flags = MEDIA_PAD_FL_SOURCE;
+       dev->format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
+       dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+
+       ret =
+           v4l2_ctrl_handler_init(&dev->ctrl_handler,
+                                  ARRAY_SIZE(mt9m114_controls));
+       if (ret) {
+               mt9m114_remove(client);
+               return ret;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(mt9m114_controls); i++)
+               v4l2_ctrl_new_custom(&dev->ctrl_handler, &mt9m114_controls[i],
+                                    NULL);
+
+       if (dev->ctrl_handler.error) {
+               mt9m114_remove(client);
+               return dev->ctrl_handler.error;
+       }
+
+       /* Use same lock for controls as for everything else. */
+       dev->ctrl_handler.lock = &dev->input_lock;
+       dev->sd.ctrl_handler = &dev->ctrl_handler;
+
+       /* REVISIT: Do we need media controller? */
+       ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad);
+       if (ret) {
+               mt9m114_remove(client);
+               return ret;
+       }
+       return 0;
+}
+
+MODULE_DEVICE_TABLE(i2c, mt9m114_id);
+
+static const struct acpi_device_id mt9m114_acpi_match[] = {
+       { "INT33F0" },
+       { "CRMT1040" },
+       {},
+};
+
+MODULE_DEVICE_TABLE(acpi, mt9m114_acpi_match);
+
+static struct i2c_driver mt9m114_driver = {
+       .driver = {
+               .name = "mt9m114",
+               .acpi_match_table = ACPI_PTR(mt9m114_acpi_match),
+       },
+       .probe = mt9m114_probe,
+       .remove = mt9m114_remove,
+       .id_table = mt9m114_id,
+};
+
+static __init int init_mt9m114(void)
+{
+       return i2c_add_driver(&mt9m114_driver);
+}
+
+static __exit void exit_mt9m114(void)
+{
+       i2c_del_driver(&mt9m114_driver);
+}
+
+module_init(init_mt9m114);
+module_exit(exit_mt9m114);
+
+MODULE_AUTHOR("Shuguang Gong <Shuguang.gong@intel.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c
new file mode 100644 (file)
index 0000000..51b7d61
--- /dev/null
@@ -0,0 +1,1557 @@
+/*
+ * Support for OmniVision OV2680 1080p HD camera sensor.
+ *
+ * Copyright (c) 2013 Intel Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kmod.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/moduleparam.h>
+#include <media/v4l2-device.h>
+#include <linux/io.h>
+#include <linux/acpi.h>
+#include "../include/linux/atomisp_gmin_platform.h"
+
+#include "ov2680.h"
+
+static int h_flag = 0;
+static int v_flag = 0;
+static enum atomisp_bayer_order ov2680_bayer_order_mapping[] = {
+       atomisp_bayer_order_bggr,
+       atomisp_bayer_order_grbg,
+       atomisp_bayer_order_gbrg,
+       atomisp_bayer_order_rggb,
+};
+
+/* i2c read/write stuff */
+static int ov2680_read_reg(struct i2c_client *client,
+                          u16 data_length, u16 reg, u16 *val)
+{
+       int err;
+       struct i2c_msg msg[2];
+       unsigned char data[6];
+
+       if (!client->adapter) {
+               dev_err(&client->dev, "%s error, no client->adapter\n",
+                       __func__);
+               return -ENODEV;
+       }
+
+       if (data_length != OV2680_8BIT && data_length != OV2680_16BIT
+                                       && data_length != OV2680_32BIT) {
+               dev_err(&client->dev, "%s error, invalid data length\n",
+                       __func__);
+               return -EINVAL;
+       }
+
+       memset(msg, 0 , sizeof(msg));
+
+       msg[0].addr = client->addr;
+       msg[0].flags = 0;
+       msg[0].len = I2C_MSG_LENGTH;
+       msg[0].buf = data;
+
+       /* high byte goes out first */
+       data[0] = (u8)(reg >> 8);
+       data[1] = (u8)(reg & 0xff);
+
+       msg[1].addr = client->addr;
+       msg[1].len = data_length;
+       msg[1].flags = I2C_M_RD;
+       msg[1].buf = data;
+
+       err = i2c_transfer(client->adapter, msg, 2);
+       if (err != 2) {
+               if (err >= 0)
+                       err = -EIO;
+               dev_err(&client->dev,
+                       "read from offset 0x%x error %d", reg, err);
+               return err;
+       }
+
+       *val = 0;
+       /* high byte comes first */
+       if (data_length == OV2680_8BIT)
+               *val = (u8)data[0];
+       else if (data_length == OV2680_16BIT)
+               *val = be16_to_cpu(*(u16 *)&data[0]);
+       else
+               *val = be32_to_cpu(*(u32 *)&data[0]);
+       //dev_dbg(&client->dev,  "++++i2c read adr%x = %x\n", reg,*val);
+       return 0;
+}
+
+static int ov2680_i2c_write(struct i2c_client *client, u16 len, u8 *data)
+{
+       struct i2c_msg msg;
+       const int num_msg = 1;
+       int ret;
+
+       msg.addr = client->addr;
+       msg.flags = 0;
+       msg.len = len;
+       msg.buf = data;
+       ret = i2c_transfer(client->adapter, &msg, 1);
+       //dev_dbg(&client->dev,  "+++i2c write reg=%x->%x\n", data[0]*256 +data[1],data[2]);
+       return ret == num_msg ? 0 : -EIO;
+}
+
+static int ov2680_write_reg(struct i2c_client *client, u16 data_length,
+                                                       u16 reg, u16 val)
+{
+       int ret;
+       unsigned char data[4] = {0};
+       u16 *wreg = (u16 *)data;
+       const u16 len = data_length + sizeof(u16); /* 16-bit address + data */
+
+       if (data_length != OV2680_8BIT && data_length != OV2680_16BIT) {
+               dev_err(&client->dev,
+                       "%s error, invalid data_length\n", __func__);
+               return -EINVAL;
+       }
+
+       /* high byte goes out first */
+       *wreg = cpu_to_be16(reg);
+
+       if (data_length == OV2680_8BIT) {
+               data[2] = (u8)(val);
+       } else {
+               /* OV2680_16BIT */
+               u16 *wdata = (u16 *)&data[2];
+               *wdata = cpu_to_be16(val);
+       }
+
+       ret = ov2680_i2c_write(client, len, data);
+       if (ret)
+               dev_err(&client->dev,
+                       "write error: wrote 0x%x to offset 0x%x error %d",
+                       val, reg, ret);
+
+       return ret;
+}
+
+/*
+ * ov2680_write_reg_array - Initializes a list of OV2680 registers
+ * @client: i2c driver client structure
+ * @reglist: list of registers to be written
+ *
+ * This function initializes a list of registers. When consecutive addresses
+ * are found in a row on the list, this function creates a buffer and sends
+ * consecutive data in a single i2c_transfer().
+ *
+ * __ov2680_flush_reg_array, __ov2680_buf_reg_array() and
+ * __ov2680_write_reg_is_consecutive() are internal functions to
+ * ov2680_write_reg_array_fast() and should be not used anywhere else.
+ *
+ */
+
+static int __ov2680_flush_reg_array(struct i2c_client *client,
+                                   struct ov2680_write_ctrl *ctrl)
+{
+       u16 size;
+
+       if (ctrl->index == 0)
+               return 0;
+
+       size = sizeof(u16) + ctrl->index; /* 16-bit address + data */
+       ctrl->buffer.addr = cpu_to_be16(ctrl->buffer.addr);
+       ctrl->index = 0;
+
+       return ov2680_i2c_write(client, size, (u8 *)&ctrl->buffer);
+}
+
+static int __ov2680_buf_reg_array(struct i2c_client *client,
+                                 struct ov2680_write_ctrl *ctrl,
+                                 const struct ov2680_reg *next)
+{
+       int size;
+       u16 *data16;
+
+       switch (next->type) {
+       case OV2680_8BIT:
+               size = 1;
+               ctrl->buffer.data[ctrl->index] = (u8)next->val;
+               break;
+       case OV2680_16BIT:
+               size = 2;
+               data16 = (u16 *)&ctrl->buffer.data[ctrl->index];
+               *data16 = cpu_to_be16((u16)next->val);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* When first item is added, we need to store its starting address */
+       if (ctrl->index == 0)
+               ctrl->buffer.addr = next->reg;
+
+       ctrl->index += size;
+
+       /*
+        * Buffer cannot guarantee free space for u32? Better flush it to avoid
+        * possible lack of memory for next item.
+        */
+       if (ctrl->index + sizeof(u16) >= OV2680_MAX_WRITE_BUF_SIZE)
+               return __ov2680_flush_reg_array(client, ctrl);
+
+       return 0;
+}
+
+static int __ov2680_write_reg_is_consecutive(struct i2c_client *client,
+                                            struct ov2680_write_ctrl *ctrl,
+                                            const struct ov2680_reg *next)
+{
+       if (ctrl->index == 0)
+               return 1;
+
+       return ctrl->buffer.addr + ctrl->index == next->reg;
+}
+
+static int ov2680_write_reg_array(struct i2c_client *client,
+                                 const struct ov2680_reg *reglist)
+{
+       const struct ov2680_reg *next = reglist;
+       struct ov2680_write_ctrl ctrl;
+       int err;
+       dev_dbg(&client->dev,  "++++write reg array\n");
+       ctrl.index = 0;
+       for (; next->type != OV2680_TOK_TERM; next++) {
+               switch (next->type & OV2680_TOK_MASK) {
+               case OV2680_TOK_DELAY:
+                       err = __ov2680_flush_reg_array(client, &ctrl);
+                       if (err)
+                               return err;
+                       msleep(next->val);
+                       break;
+               default:
+                       /*
+                        * If next address is not consecutive, data needs to be
+                        * flushed before proceed.
+                        */
+                        dev_dbg(&client->dev,  "+++ov2680_write_reg_array reg=%x->%x\n", next->reg,next->val);
+                       if (!__ov2680_write_reg_is_consecutive(client, &ctrl,
+                                                               next)) {
+                               err = __ov2680_flush_reg_array(client, &ctrl);
+                       if (err)
+                               return err;
+                       }
+                       err = __ov2680_buf_reg_array(client, &ctrl, next);
+                       if (err) {
+                               dev_err(&client->dev, "%s: write error, aborted\n",
+                                        __func__);
+                               return err;
+                       }
+                       break;
+               }
+       }
+
+       return __ov2680_flush_reg_array(client, &ctrl);
+}
+static int ov2680_g_focal(struct v4l2_subdev *sd, s32 *val)
+{
+
+       *val = (OV2680_FOCAL_LENGTH_NUM << 16) | OV2680_FOCAL_LENGTH_DEM;
+       return 0;
+}
+
+static int ov2680_g_fnumber(struct v4l2_subdev *sd, s32 *val)
+{
+       /*const f number for ov2680*/
+
+       *val = (OV2680_F_NUMBER_DEFAULT_NUM << 16) | OV2680_F_NUMBER_DEM;
+       return 0;
+}
+
+static int ov2680_g_fnumber_range(struct v4l2_subdev *sd, s32 *val)
+{
+       *val = (OV2680_F_NUMBER_DEFAULT_NUM << 24) |
+               (OV2680_F_NUMBER_DEM << 16) |
+               (OV2680_F_NUMBER_DEFAULT_NUM << 8) | OV2680_F_NUMBER_DEM;
+       return 0;
+}
+
+static int ov2680_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val)
+{
+       struct ov2680_device *dev = to_ov2680_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       dev_dbg(&client->dev,  "++++ov2680_g_bin_factor_x\n");
+       *val = ov2680_res[dev->fmt_idx].bin_factor_x;
+
+       return 0;
+}
+
+static int ov2680_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val)
+{
+       struct ov2680_device *dev = to_ov2680_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       *val = ov2680_res[dev->fmt_idx].bin_factor_y;
+       dev_dbg(&client->dev,  "++++ov2680_g_bin_factor_y\n");
+       return 0;
+}
+
+
+static int ov2680_get_intg_factor(struct i2c_client *client,
+                               struct camera_mipi_info *info,
+                               const struct ov2680_resolution *res)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct ov2680_device *dev = to_ov2680_sensor(sd);
+       struct atomisp_sensor_mode_data *buf = &info->data;
+       unsigned int pix_clk_freq_hz;
+       u16 reg_val;
+       int ret;
+       dev_dbg(&client->dev,  "++++ov2680_get_intg_factor\n");
+       if (!info)
+               return -EINVAL;
+
+       /* pixel clock */
+       pix_clk_freq_hz = res->pix_clk_freq * 1000000;
+
+       dev->vt_pix_clk_freq_mhz = pix_clk_freq_hz;
+       buf->vt_pix_clk_freq_mhz = pix_clk_freq_hz;
+
+       /* get integration time */
+       buf->coarse_integration_time_min = OV2680_COARSE_INTG_TIME_MIN;
+       buf->coarse_integration_time_max_margin =
+                                       OV2680_COARSE_INTG_TIME_MAX_MARGIN;
+
+       buf->fine_integration_time_min = OV2680_FINE_INTG_TIME_MIN;
+       buf->fine_integration_time_max_margin =
+                                       OV2680_FINE_INTG_TIME_MAX_MARGIN;
+
+       buf->fine_integration_time_def = OV2680_FINE_INTG_TIME_MIN;
+       buf->frame_length_lines = res->lines_per_frame;
+       buf->line_length_pck = res->pixels_per_line;
+       buf->read_mode = res->bin_mode;
+
+       /* get the cropping and output resolution to ISP for this mode. */
+       ret =  ov2680_read_reg(client, OV2680_16BIT,
+                                       OV2680_HORIZONTAL_START_H, &reg_val);
+       if (ret)
+               return ret;
+       buf->crop_horizontal_start = reg_val;
+
+       ret =  ov2680_read_reg(client, OV2680_16BIT,
+                                       OV2680_VERTICAL_START_H, &reg_val);
+       if (ret)
+               return ret;
+       buf->crop_vertical_start = reg_val;
+
+       ret = ov2680_read_reg(client, OV2680_16BIT,
+                                       OV2680_HORIZONTAL_END_H, &reg_val);
+       if (ret)
+               return ret;
+       buf->crop_horizontal_end = reg_val;
+
+       ret = ov2680_read_reg(client, OV2680_16BIT,
+                                       OV2680_VERTICAL_END_H, &reg_val);
+       if (ret)
+               return ret;
+       buf->crop_vertical_end = reg_val;
+
+       ret = ov2680_read_reg(client, OV2680_16BIT,
+                                       OV2680_HORIZONTAL_OUTPUT_SIZE_H, &reg_val);
+       if (ret)
+               return ret;
+       buf->output_width = reg_val;
+
+       ret = ov2680_read_reg(client, OV2680_16BIT,
+                                       OV2680_VERTICAL_OUTPUT_SIZE_H, &reg_val);
+       if (ret)
+               return ret;
+       buf->output_height = reg_val;
+
+       buf->binning_factor_x = res->bin_factor_x ?
+                                       (res->bin_factor_x * 2) : 1;
+       buf->binning_factor_y = res->bin_factor_y ?
+                                       (res->bin_factor_y * 2) : 1;
+       return 0;
+}
+
+static long __ov2680_set_exposure(struct v4l2_subdev *sd, int coarse_itg,
+                                int gain, int digitgain)
+
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct ov2680_device *dev = to_ov2680_sensor(sd);
+       u16 vts,hts;
+       int ret,exp_val;
+
+       dev_dbg(&client->dev, "+++++++__ov2680_set_exposure coarse_itg %d, gain %d, digitgain %d++\n",coarse_itg, gain, digitgain);
+
+       hts = ov2680_res[dev->fmt_idx].pixels_per_line;
+       vts = ov2680_res[dev->fmt_idx].lines_per_frame;
+
+       /* group hold */
+       ret = ov2680_write_reg(client, OV2680_8BIT,
+                                       OV2680_GROUP_ACCESS, 0x00);
+       if (ret) {
+               dev_err(&client->dev, "%s: write %x error, aborted\n",
+                       __func__, OV2680_GROUP_ACCESS);
+               return ret;
+       }
+
+       /* Increase the VTS to match exposure + MARGIN */
+       if (coarse_itg > vts - OV2680_INTEGRATION_TIME_MARGIN)
+               vts = (u16) coarse_itg + OV2680_INTEGRATION_TIME_MARGIN;
+
+       ret = ov2680_write_reg(client, OV2680_16BIT, OV2680_TIMING_VTS_H, vts);
+       if (ret) {
+               dev_err(&client->dev, "%s: write %x error, aborted\n",
+                       __func__, OV2680_TIMING_VTS_H);
+               return ret;
+       }
+
+       /* set exposure */
+
+       /* Lower four bit should be 0*/
+       exp_val = coarse_itg << 4;
+       ret = ov2680_write_reg(client, OV2680_8BIT,
+                              OV2680_EXPOSURE_L, exp_val & 0xFF);
+       if (ret) {
+               dev_err(&client->dev, "%s: write %x error, aborted\n",
+                       __func__, OV2680_EXPOSURE_L);
+               return ret;
+       }
+
+       ret = ov2680_write_reg(client, OV2680_8BIT,
+                              OV2680_EXPOSURE_M, (exp_val >> 8) & 0xFF);
+       if (ret) {
+               dev_err(&client->dev, "%s: write %x error, aborted\n",
+                       __func__, OV2680_EXPOSURE_M);
+               return ret;
+       }
+
+       ret = ov2680_write_reg(client, OV2680_8BIT,
+                              OV2680_EXPOSURE_H, (exp_val >> 16) & 0x0F);
+       if (ret) {
+               dev_err(&client->dev, "%s: write %x error, aborted\n",
+                       __func__, OV2680_EXPOSURE_H);
+               return ret;
+       }
+
+       /* Analog gain */
+       ret = ov2680_write_reg(client, OV2680_16BIT, OV2680_AGC_H, gain);
+       if (ret) {
+               dev_err(&client->dev, "%s: write %x error, aborted\n",
+                       __func__, OV2680_AGC_H);
+               return ret;
+       }
+       /* Digital gain */
+       if (digitgain) {
+               ret = ov2680_write_reg(client, OV2680_16BIT,
+                               OV2680_MWB_RED_GAIN_H, digitgain);
+               if (ret) {
+                       dev_err(&client->dev, "%s: write %x error, aborted\n",
+                               __func__, OV2680_MWB_RED_GAIN_H);
+                       return ret;
+               }
+
+               ret = ov2680_write_reg(client, OV2680_16BIT,
+                               OV2680_MWB_GREEN_GAIN_H, digitgain);
+               if (ret) {
+                       dev_err(&client->dev, "%s: write %x error, aborted\n",
+                               __func__, OV2680_MWB_RED_GAIN_H);
+                       return ret;
+               }
+
+               ret = ov2680_write_reg(client, OV2680_16BIT,
+                               OV2680_MWB_BLUE_GAIN_H, digitgain);
+               if (ret) {
+                       dev_err(&client->dev, "%s: write %x error, aborted\n",
+                               __func__, OV2680_MWB_RED_GAIN_H);
+                       return ret;
+               }
+       }
+
+       /* End group */
+       ret = ov2680_write_reg(client, OV2680_8BIT,
+                              OV2680_GROUP_ACCESS, 0x10);
+       if (ret)
+               return ret;
+
+       /* Delay launch group */
+       ret = ov2680_write_reg(client, OV2680_8BIT,
+                                          OV2680_GROUP_ACCESS, 0xa0);
+       if (ret)
+               return ret;
+       return ret;
+}
+
+static int ov2680_set_exposure(struct v4l2_subdev *sd, int exposure,
+       int gain, int digitgain)
+{
+       struct ov2680_device *dev = to_ov2680_sensor(sd);
+       int ret;
+
+       mutex_lock(&dev->input_lock);
+       ret = __ov2680_set_exposure(sd, exposure, gain, digitgain);
+       mutex_unlock(&dev->input_lock);
+
+       return ret;
+}
+
+static long ov2680_s_exposure(struct v4l2_subdev *sd,
+                              struct atomisp_exposure *exposure)
+{
+       u16 coarse_itg = exposure->integration_time[0];
+       u16 analog_gain = exposure->gain[0];
+       u16 digital_gain = exposure->gain[1];
+
+       /* we should not accept the invalid value below */
+       if (analog_gain == 0) {
+               struct i2c_client *client = v4l2_get_subdevdata(sd);
+               v4l2_err(client, "%s: invalid value\n", __func__);
+               return -EINVAL;
+       }
+
+       // EXPOSURE CONTROL DISABLED FOR INITIAL CHECKIN, TUNING DOESN'T WORK
+       return ov2680_set_exposure(sd, coarse_itg, analog_gain, digital_gain);
+}
+
+
+
+
+
+static long ov2680_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+
+       switch (cmd) {
+       case ATOMISP_IOC_S_EXPOSURE:
+               return ov2680_s_exposure(sd, arg);
+
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/* This returns the exposure time being used. This should only be used
+ * for filling in EXIF data, not for actual image processing.
+ */
+static int ov2680_q_exposure(struct v4l2_subdev *sd, s32 *value)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       u16 reg_v, reg_v2;
+       int ret;
+
+       /* get exposure */
+       ret = ov2680_read_reg(client, OV2680_8BIT,
+                                       OV2680_EXPOSURE_L,
+                                       &reg_v);
+       if (ret)
+               goto err;
+
+       ret = ov2680_read_reg(client, OV2680_8BIT,
+                                       OV2680_EXPOSURE_M,
+                                       &reg_v2);
+       if (ret)
+               goto err;
+
+       reg_v += reg_v2 << 8;
+       ret = ov2680_read_reg(client, OV2680_8BIT,
+                                       OV2680_EXPOSURE_H,
+                                       &reg_v2);
+       if (ret)
+               goto err;
+
+       *value = reg_v + (((u32)reg_v2 << 16));
+err:
+       return ret;
+}
+
+static u32 ov2680_translate_bayer_order(enum atomisp_bayer_order code)
+{
+       switch (code) {
+       case atomisp_bayer_order_rggb:
+               return MEDIA_BUS_FMT_SRGGB10_1X10;
+       case atomisp_bayer_order_grbg:
+               return MEDIA_BUS_FMT_SGRBG10_1X10;
+       case atomisp_bayer_order_bggr:
+               return MEDIA_BUS_FMT_SBGGR10_1X10;
+       case atomisp_bayer_order_gbrg:
+               return MEDIA_BUS_FMT_SGBRG10_1X10;
+       }
+       return 0;
+}
+
+static int ov2680_v_flip(struct v4l2_subdev *sd, s32 value)
+{
+       struct ov2680_device *dev = to_ov2680_sensor(sd);
+       struct camera_mipi_info *ov2680_info = NULL;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret;
+       u16 val;
+       u8 index;
+       dev_dbg(&client->dev, "@%s: value:%d\n", __func__, value);
+       ret = ov2680_read_reg(client, OV2680_8BIT, OV2680_FLIP_REG, &val);
+       if (ret)
+               return ret;
+       if (value) {
+               val |= OV2680_FLIP_MIRROR_BIT_ENABLE;
+       } else {
+               val &= ~OV2680_FLIP_MIRROR_BIT_ENABLE;
+       }
+       ret = ov2680_write_reg(client, OV2680_8BIT,
+                       OV2680_FLIP_REG, val);
+       if (ret)
+               return ret;
+       index = (v_flag>0?OV2680_FLIP_BIT:0) | (h_flag>0?OV2680_MIRROR_BIT:0);
+       ov2680_info = v4l2_get_subdev_hostdata(sd);
+       if (ov2680_info) {
+               ov2680_info->raw_bayer_order = ov2680_bayer_order_mapping[index];
+               dev->format.code = ov2680_translate_bayer_order(
+                       ov2680_info->raw_bayer_order);
+       }
+       return ret;
+}
+
+static int ov2680_h_flip(struct v4l2_subdev *sd, s32 value)
+{
+       struct ov2680_device *dev = to_ov2680_sensor(sd);
+       struct camera_mipi_info *ov2680_info = NULL;
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret;
+       u16 val;
+       u8 index;
+       dev_dbg(&client->dev, "@%s: value:%d\n", __func__, value);
+
+       ret = ov2680_read_reg(client, OV2680_8BIT, OV2680_MIRROR_REG, &val);
+       if (ret)
+               return ret;
+       if (value) {
+               val |= OV2680_FLIP_MIRROR_BIT_ENABLE;
+       } else {
+               val &= ~OV2680_FLIP_MIRROR_BIT_ENABLE;
+       }
+       ret = ov2680_write_reg(client, OV2680_8BIT,
+                       OV2680_MIRROR_REG, val);
+       if (ret)
+               return ret;
+       index = (v_flag>0?OV2680_FLIP_BIT:0) | (h_flag>0?OV2680_MIRROR_BIT:0);
+       ov2680_info = v4l2_get_subdev_hostdata(sd);
+       if (ov2680_info) {
+               ov2680_info->raw_bayer_order = ov2680_bayer_order_mapping[index];
+               dev->format.code = ov2680_translate_bayer_order(
+                       ov2680_info->raw_bayer_order);
+       }
+       return ret;
+}
+
+static int ov2680_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct ov2680_device *dev =
+           container_of(ctrl->handler, struct ov2680_device, ctrl_handler);
+       struct i2c_client *client = v4l2_get_subdevdata(&dev->sd);
+       int ret = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_VFLIP:
+               dev_dbg(&client->dev, "%s: CID_VFLIP:%d.\n",
+                       __func__, ctrl->val);
+               ret = ov2680_v_flip(&dev->sd, ctrl->val);
+               break;
+       case V4L2_CID_HFLIP:
+               dev_dbg(&client->dev, "%s: CID_HFLIP:%d.\n",
+                       __func__, ctrl->val);
+               ret = ov2680_h_flip(&dev->sd, ctrl->val);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+       return ret;
+}
+
+static int ov2680_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct ov2680_device *dev =
+           container_of(ctrl->handler, struct ov2680_device, ctrl_handler);
+       int ret = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE_ABSOLUTE:
+               ret = ov2680_q_exposure(&dev->sd, &ctrl->val);
+               break;
+       case V4L2_CID_FOCAL_ABSOLUTE:
+               ret = ov2680_g_focal(&dev->sd, &ctrl->val);
+               break;
+       case V4L2_CID_FNUMBER_ABSOLUTE:
+               ret = ov2680_g_fnumber(&dev->sd, &ctrl->val);
+               break;
+       case V4L2_CID_FNUMBER_RANGE:
+               ret = ov2680_g_fnumber_range(&dev->sd, &ctrl->val);
+               break;
+       case V4L2_CID_BIN_FACTOR_HORZ:
+               ret = ov2680_g_bin_factor_x(&dev->sd, &ctrl->val);
+               break;
+       case V4L2_CID_BIN_FACTOR_VERT:
+               ret = ov2680_g_bin_factor_y(&dev->sd, &ctrl->val);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static const struct v4l2_ctrl_ops ctrl_ops = {
+       .s_ctrl = ov2680_s_ctrl,
+       .g_volatile_ctrl = ov2680_g_volatile_ctrl
+};
+
+struct v4l2_ctrl_config ov2680_controls[] = {
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_EXPOSURE_ABSOLUTE,
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .name = "exposure",
+        .min = 0x0,
+        .max = 0xffff,
+        .step = 0x01,
+        .def = 0x00,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_FOCAL_ABSOLUTE,
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .name = "focal length",
+        .min = OV2680_FOCAL_LENGTH_DEFAULT,
+        .max = OV2680_FOCAL_LENGTH_DEFAULT,
+        .step = 0x01,
+        .def = OV2680_FOCAL_LENGTH_DEFAULT,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_FNUMBER_ABSOLUTE,
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .name = "f-number",
+        .min = OV2680_F_NUMBER_DEFAULT,
+        .max = OV2680_F_NUMBER_DEFAULT,
+        .step = 0x01,
+        .def = OV2680_F_NUMBER_DEFAULT,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_FNUMBER_RANGE,
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .name = "f-number range",
+        .min = OV2680_F_NUMBER_RANGE,
+        .max = OV2680_F_NUMBER_RANGE,
+        .step = 0x01,
+        .def = OV2680_F_NUMBER_RANGE,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_BIN_FACTOR_HORZ,
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .name = "horizontal binning factor",
+        .min = 0,
+        .max = OV2680_BIN_FACTOR_MAX,
+        .step = 1,
+        .def = 0,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_BIN_FACTOR_VERT,
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .name = "vertical binning factor",
+        .min = 0,
+        .max = OV2680_BIN_FACTOR_MAX,
+        .step = 1,
+        .def = 0,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_VFLIP,
+        .type = V4L2_CTRL_TYPE_BOOLEAN,
+        .name = "Flip",
+        .min = 0,
+        .max = 1,
+        .step = 1,
+        .def = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_HFLIP,
+        .type = V4L2_CTRL_TYPE_BOOLEAN,
+        .name = "Mirror",
+        .min = 0,
+        .max = 1,
+        .step = 1,
+        .def = 0,
+        },
+};
+
+static int ov2680_init_registers(struct v4l2_subdev *sd)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret;
+
+       ret = ov2680_write_reg(client, OV2680_8BIT, OV2680_SW_RESET, 0x01);
+       ret |= ov2680_write_reg_array(client, ov2680_global_setting);
+
+       return ret;
+}
+
+static int ov2680_init(struct v4l2_subdev *sd)
+{
+       struct ov2680_device *dev = to_ov2680_sensor(sd);
+
+       int ret;
+
+       mutex_lock(&dev->input_lock);
+
+       /* restore settings */
+       ov2680_res = ov2680_res_preview;
+       N_RES = N_RES_PREVIEW;
+
+       ret = ov2680_init_registers(sd);
+
+       mutex_unlock(&dev->input_lock);
+
+       return ret;
+}
+
+static int power_ctrl(struct v4l2_subdev *sd, bool flag)
+{
+       int ret = 0;
+       struct ov2680_device *dev = to_ov2680_sensor(sd);
+       if (!dev || !dev->platform_data)
+               return -ENODEV;
+
+       /* Non-gmin platforms use the legacy callback */
+       if (dev->platform_data->power_ctrl)
+               return dev->platform_data->power_ctrl(sd, flag);
+
+       if (flag) {
+               ret |= dev->platform_data->v1p8_ctrl(sd, 1);
+               ret |= dev->platform_data->v2p8_ctrl(sd, 1);
+               usleep_range(10000, 15000);
+       }
+
+       if (!flag || ret) {
+               ret |= dev->platform_data->v1p8_ctrl(sd, 0);
+               ret |= dev->platform_data->v2p8_ctrl(sd, 0);
+       }
+       return ret;
+}
+
+static int gpio_ctrl(struct v4l2_subdev *sd, bool flag)
+{
+       int ret;
+       struct ov2680_device *dev = to_ov2680_sensor(sd);
+
+       if (!dev || !dev->platform_data)
+               return -ENODEV;
+
+       /* Non-gmin platforms use the legacy callback */
+       if (dev->platform_data->gpio_ctrl)
+               return dev->platform_data->gpio_ctrl(sd, flag);
+
+       /* The OV2680 documents only one GPIO input (#XSHUTDN), but
+        * existing integrations often wire two (reset/power_down)
+        * because that is the way other sensors work.  There is no
+        * way to tell how it is wired internally, so existing
+        * firmwares expose both and we drive them symmetrically. */
+       if (flag) {
+               ret = dev->platform_data->gpio0_ctrl(sd, 1);
+               usleep_range(10000, 15000);
+               /* Ignore return from second gpio, it may not be there */
+               dev->platform_data->gpio1_ctrl(sd, 1);
+               usleep_range(10000, 15000);
+       } else {
+               dev->platform_data->gpio1_ctrl(sd, 0);
+               ret = dev->platform_data->gpio0_ctrl(sd, 0);
+       }
+       return ret;
+}
+
+static int power_up(struct v4l2_subdev *sd)
+{
+       struct ov2680_device *dev = to_ov2680_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret;
+
+       if (!dev->platform_data) {
+               dev_err(&client->dev,
+                       "no camera_sensor_platform_data");
+               return -ENODEV;
+       }
+
+       /* power control */
+       ret = power_ctrl(sd, 1);
+       if (ret)
+               goto fail_power;
+
+       /* according to DS, at least 5ms is needed between DOVDD and PWDN */
+       usleep_range(5000, 6000);
+
+       /* gpio ctrl */
+       ret = gpio_ctrl(sd, 1);
+       if (ret) {
+               ret = gpio_ctrl(sd, 1);
+               if (ret)
+                       goto fail_power;
+       }
+
+       /* flis clock control */
+       ret = dev->platform_data->flisclk_ctrl(sd, 1);
+       if (ret)
+               goto fail_clk;
+
+       /* according to DS, 20ms is needed between PWDN and i2c access */
+       msleep(20);
+
+       return 0;
+
+fail_clk:
+       gpio_ctrl(sd, 0);
+fail_power:
+       power_ctrl(sd, 0);
+       dev_err(&client->dev, "sensor power-up failed\n");
+
+       return ret;
+}
+
+static int power_down(struct v4l2_subdev *sd)
+{
+       struct ov2680_device *dev = to_ov2680_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret = 0;
+
+       h_flag = 0;
+       v_flag = 0;
+       if (!dev->platform_data) {
+               dev_err(&client->dev,
+                       "no camera_sensor_platform_data");
+               return -ENODEV;
+       }
+
+       ret = dev->platform_data->flisclk_ctrl(sd, 0);
+       if (ret)
+               dev_err(&client->dev, "flisclk failed\n");
+
+       /* gpio ctrl */
+       ret = gpio_ctrl(sd, 0);
+       if (ret) {
+               ret = gpio_ctrl(sd, 0);
+               if (ret)
+                       dev_err(&client->dev, "gpio failed 2\n");
+       }
+
+       /* power control */
+       ret = power_ctrl(sd, 0);
+       if (ret)
+               dev_err(&client->dev, "vprog failed.\n");
+
+       return ret;
+}
+
+static int ov2680_s_power(struct v4l2_subdev *sd, int on)
+{
+       int ret;
+
+       if (on == 0){
+               ret = power_down(sd);
+       } else {
+               ret = power_up(sd);
+               if (!ret)
+                       return ov2680_init(sd);
+       }
+       return ret;
+}
+
+/*
+ * distance - calculate the distance
+ * @res: resolution
+ * @w: width
+ * @h: height
+ *
+ * Get the gap between resolution and w/h.
+ * res->width/height smaller than w/h wouldn't be considered.
+ * Returns the value of gap or -1 if fail.
+ */
+#define LARGEST_ALLOWED_RATIO_MISMATCH 600
+static int distance(struct ov2680_resolution *res, u32 w, u32 h)
+{
+       unsigned int w_ratio = (res->width << 13) / w;
+       unsigned int h_ratio;
+       int match;
+
+       if (h == 0)
+               return -1;
+       h_ratio = (res->height << 13) / h;
+       if (h_ratio == 0)
+               return -1;
+       match   = abs(((w_ratio << 13) / h_ratio) - ((int)8192));
+
+
+       if ((w_ratio < (int)8192) || (h_ratio < (int)8192)  ||
+               (match > LARGEST_ALLOWED_RATIO_MISMATCH))
+               return -1;
+
+       return w_ratio + h_ratio;
+}
+
+/* Return the nearest higher resolution index */
+static int nearest_resolution_index(int w, int h)
+{
+       int i;
+       int idx = -1;
+       int dist;
+       int min_dist = INT_MAX;
+       struct ov2680_resolution *tmp_res = NULL;
+
+       for (i = 0; i < N_RES; i++) {
+               tmp_res = &ov2680_res[i];
+               dist = distance(tmp_res, w, h);
+               if (dist == -1)
+                       continue;
+               if (dist < min_dist) {
+                       min_dist = dist;
+                       idx = i;
+               }
+       }
+
+       return idx;
+}
+
+static int get_resolution_index(int w, int h)
+{
+       int i;
+
+       for (i = 0; i < N_RES; i++) {
+               if (w != ov2680_res[i].width)
+                       continue;
+               if (h != ov2680_res[i].height)
+                       continue;
+
+               return i;
+       }
+
+       return -1;
+}
+
+static int ov2680_set_fmt(struct v4l2_subdev *sd,
+                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_format *format)
+{
+       struct v4l2_mbus_framefmt *fmt = &format->format;
+       struct ov2680_device *dev = to_ov2680_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct camera_mipi_info *ov2680_info = NULL;
+       int ret = 0;
+       int idx = 0;
+       dev_dbg(&client->dev, "+++++ov2680_s_mbus_fmt+++++l\n");
+       if (format->pad)
+               return -EINVAL;
+
+       if (!fmt)
+               return -EINVAL;
+
+       ov2680_info = v4l2_get_subdev_hostdata(sd);
+       if (!ov2680_info)
+               return -EINVAL;
+
+       mutex_lock(&dev->input_lock);
+       idx = nearest_resolution_index(fmt->width, fmt->height);
+       if (idx == -1) {
+               /* return the largest resolution */
+               fmt->width = ov2680_res[N_RES - 1].width;
+               fmt->height = ov2680_res[N_RES - 1].height;
+       } else {
+               fmt->width = ov2680_res[idx].width;
+               fmt->height = ov2680_res[idx].height;
+       }
+       fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
+       if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+               cfg->try_fmt = *fmt;
+               mutex_unlock(&dev->input_lock);
+               return 0;
+               }
+       dev->fmt_idx = get_resolution_index(fmt->width, fmt->height);
+       dev_dbg(&client->dev, "+++++get_resolution_index=%d+++++l\n",
+                    dev->fmt_idx);
+       if (dev->fmt_idx == -1) {
+               dev_err(&client->dev, "get resolution fail\n");
+               mutex_unlock(&dev->input_lock);
+               return -EINVAL;
+       }
+       v4l2_info(client, "__s_mbus_fmt i=%d, w=%d, h=%d\n", dev->fmt_idx,
+                 fmt->width, fmt->height);
+       dev_dbg(&client->dev, "__s_mbus_fmt i=%d, w=%d, h=%d\n",
+                    dev->fmt_idx, fmt->width, fmt->height);
+
+       ret = ov2680_write_reg_array(client, ov2680_res[dev->fmt_idx].regs);
+       if (ret)
+               dev_err(&client->dev, "ov2680 write resolution register err\n");
+
+       ret = ov2680_get_intg_factor(client, ov2680_info,
+                                    &ov2680_res[dev->fmt_idx]);
+       if (ret) {
+               dev_err(&client->dev, "failed to get integration_factor\n");
+               goto err;
+       }
+
+       /*recall flip functions to avoid flip registers
+        * were overridden by default setting
+        */
+       if (h_flag)
+               ov2680_h_flip(sd, h_flag);
+       if (v_flag)
+               ov2680_v_flip(sd, v_flag);
+
+       v4l2_info(client, "\n%s idx %d \n", __func__, dev->fmt_idx);
+
+       /*ret = startup(sd);
+        * if (ret)
+        * dev_err(&client->dev, "ov2680 startup err\n");
+        */
+err:
+       mutex_unlock(&dev->input_lock);
+       return ret;
+}
+
+static int ov2680_get_fmt(struct v4l2_subdev *sd,
+                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_format *format)
+{
+       struct v4l2_mbus_framefmt *fmt = &format->format;
+       struct ov2680_device *dev = to_ov2680_sensor(sd);
+
+       if (format->pad)
+               return -EINVAL;
+
+       if (!fmt)
+               return -EINVAL;
+
+       fmt->width = ov2680_res[dev->fmt_idx].width;
+       fmt->height = ov2680_res[dev->fmt_idx].height;
+       fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
+
+       return 0;
+}
+
+static int ov2680_detect(struct i2c_client *client)
+{
+       struct i2c_adapter *adapter = client->adapter;
+       u16 high, low;
+       int ret;
+       u16 id;
+       u8 revision;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
+               return -ENODEV;
+
+       ret = ov2680_read_reg(client, OV2680_8BIT,
+                                       OV2680_SC_CMMN_CHIP_ID_H, &high);
+       if (ret) {
+               dev_err(&client->dev, "sensor_id_high = 0x%x\n", high);
+               return -ENODEV;
+       }
+       ret = ov2680_read_reg(client, OV2680_8BIT,
+                                       OV2680_SC_CMMN_CHIP_ID_L, &low);
+       id = ((((u16) high) << 8) | (u16) low);
+
+       if (id != OV2680_ID) {
+               dev_err(&client->dev, "sensor ID error 0x%x\n", id);
+               return -ENODEV;
+       }
+
+       ret = ov2680_read_reg(client, OV2680_8BIT,
+                                       OV2680_SC_CMMN_SUB_ID, &high);
+       revision = (u8) high & 0x0f;
+
+       dev_info(&client->dev, "sensor_revision id = 0x%x\n", id);
+
+       return 0;
+}
+
+static int ov2680_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct ov2680_device *dev = to_ov2680_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret;
+
+       mutex_lock(&dev->input_lock);
+       if(enable )
+               dev_dbg(&client->dev, "ov2680_s_stream one \n");
+       else
+               dev_dbg(&client->dev, "ov2680_s_stream off \n");
+
+       ret = ov2680_write_reg(client, OV2680_8BIT, OV2680_SW_STREAM,
+                               enable ? OV2680_START_STREAMING :
+                               OV2680_STOP_STREAMING);
+#if 0
+       /* restore settings */
+       ov2680_res = ov2680_res_preview;
+       N_RES = N_RES_PREVIEW;
+#endif
+
+       //otp valid at stream on state
+       //if(!dev->otp_data)
+       //      dev->otp_data = ov2680_otp_read(sd);
+
+       mutex_unlock(&dev->input_lock);
+
+       return ret;
+}
+
+
+static int ov2680_s_config(struct v4l2_subdev *sd,
+                          int irq, void *platform_data)
+{
+       struct ov2680_device *dev = to_ov2680_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret = 0;
+
+       if (!platform_data)
+               return -ENODEV;
+
+       dev->platform_data =
+               (struct camera_sensor_platform_data *)platform_data;
+
+       mutex_lock(&dev->input_lock);
+       /* power off the module, then power on it in future
+        * as first power on by board may not fulfill the
+        * power on sequqence needed by the module
+        */
+       ret = power_down(sd);
+       if (ret) {
+               dev_err(&client->dev, "ov2680 power-off err.\n");
+               goto fail_power_off;
+       }
+
+       ret = power_up(sd);
+       if (ret) {
+               dev_err(&client->dev, "ov2680 power-up err.\n");
+               goto fail_power_on;
+       }
+
+       ret = dev->platform_data->csi_cfg(sd, 1);
+       if (ret)
+               goto fail_csi_cfg;
+
+       /* config & detect sensor */
+       ret = ov2680_detect(client);
+       if (ret) {
+               dev_err(&client->dev, "ov2680_detect err s_config.\n");
+               goto fail_csi_cfg;
+       }
+
+       /* turn off sensor, after probed */
+       ret = power_down(sd);
+       if (ret) {
+               dev_err(&client->dev, "ov2680 power-off err.\n");
+               goto fail_csi_cfg;
+       }
+       mutex_unlock(&dev->input_lock);
+
+       return 0;
+
+fail_csi_cfg:
+       dev->platform_data->csi_cfg(sd, 0);
+fail_power_on:
+       power_down(sd);
+       dev_err(&client->dev, "sensor power-gating failed\n");
+fail_power_off:
+       mutex_unlock(&dev->input_lock);
+       return ret;
+}
+
+static int ov2680_g_parm(struct v4l2_subdev *sd,
+                       struct v4l2_streamparm *param)
+{
+       struct ov2680_device *dev = to_ov2680_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (!param)
+               return -EINVAL;
+
+       if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               dev_err(&client->dev,  "unsupported buffer type.\n");
+               return -EINVAL;
+       }
+
+       memset(param, 0, sizeof(*param));
+       param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+       if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) {
+               param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+               param->parm.capture.timeperframe.numerator = 1;
+               param->parm.capture.capturemode = dev->run_mode;
+               param->parm.capture.timeperframe.denominator =
+                       ov2680_res[dev->fmt_idx].fps;
+       }
+       return 0;
+}
+
+static int ov2680_s_parm(struct v4l2_subdev *sd,
+                       struct v4l2_streamparm *param)
+{
+       struct ov2680_device *dev = to_ov2680_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       dev->run_mode = param->parm.capture.capturemode;
+
+       v4l2_info(client, "\n%s:run_mode :%x\n", __func__, dev->run_mode);
+
+       mutex_lock(&dev->input_lock);
+       switch (dev->run_mode) {
+       case CI_MODE_VIDEO:
+               ov2680_res = ov2680_res_video;
+               N_RES = N_RES_VIDEO;
+               break;
+       case CI_MODE_STILL_CAPTURE:
+               ov2680_res = ov2680_res_still;
+               N_RES = N_RES_STILL;
+               break;
+       default:
+               ov2680_res = ov2680_res_preview;
+               N_RES = N_RES_PREVIEW;
+       }
+       mutex_unlock(&dev->input_lock);
+       return 0;
+}
+
+static int ov2680_g_frame_interval(struct v4l2_subdev *sd,
+                                  struct v4l2_subdev_frame_interval *interval)
+{
+       struct ov2680_device *dev = to_ov2680_sensor(sd);
+
+       interval->interval.numerator = 1;
+       interval->interval.denominator = ov2680_res[dev->fmt_idx].fps;
+
+       return 0;
+}
+
+static int ov2680_enum_mbus_code(struct v4l2_subdev *sd,
+                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_mbus_code_enum *code)
+{
+       if (code->index >= MAX_FMTS)
+               return -EINVAL;
+
+       code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
+       return 0;
+}
+
+static int ov2680_enum_frame_size(struct v4l2_subdev *sd,
+                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_frame_size_enum *fse)
+{
+       int index = fse->index;
+
+       if (index >= N_RES)
+               return -EINVAL;
+
+       fse->min_width = ov2680_res[index].width;
+       fse->min_height = ov2680_res[index].height;
+       fse->max_width = ov2680_res[index].width;
+       fse->max_height = ov2680_res[index].height;
+
+       return 0;
+
+}
+
+static int ov2680_g_skip_frames(struct v4l2_subdev *sd, u32 *frames)
+{
+       struct ov2680_device *dev = to_ov2680_sensor(sd);
+
+       mutex_lock(&dev->input_lock);
+       *frames = ov2680_res[dev->fmt_idx].skip_frames;
+       mutex_unlock(&dev->input_lock);
+
+       return 0;
+}
+
+static const struct v4l2_subdev_video_ops ov2680_video_ops = {
+       .s_stream = ov2680_s_stream,
+       .g_parm = ov2680_g_parm,
+       .s_parm = ov2680_s_parm,
+       .g_frame_interval = ov2680_g_frame_interval,
+};
+
+static const struct v4l2_subdev_sensor_ops ov2680_sensor_ops = {
+               .g_skip_frames  = ov2680_g_skip_frames,
+};
+
+static const struct v4l2_subdev_core_ops ov2680_core_ops = {
+       .s_power = ov2680_s_power,
+       .ioctl = ov2680_ioctl,
+};
+
+static const struct v4l2_subdev_pad_ops ov2680_pad_ops = {
+       .enum_mbus_code = ov2680_enum_mbus_code,
+       .enum_frame_size = ov2680_enum_frame_size,
+       .get_fmt = ov2680_get_fmt,
+       .set_fmt = ov2680_set_fmt,
+};
+
+static const struct v4l2_subdev_ops ov2680_ops = {
+       .core = &ov2680_core_ops,
+       .video = &ov2680_video_ops,
+       .pad = &ov2680_pad_ops,
+       .sensor = &ov2680_sensor_ops,
+};
+
+static int ov2680_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct ov2680_device *dev = to_ov2680_sensor(sd);
+       dev_dbg(&client->dev, "ov2680_remove...\n");
+
+       dev->platform_data->csi_cfg(sd, 0);
+
+       v4l2_device_unregister_subdev(sd);
+       media_entity_cleanup(&dev->sd.entity);
+       v4l2_ctrl_handler_free(&dev->ctrl_handler);
+       kfree(dev);
+
+       return 0;
+}
+
+static int ov2680_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct ov2680_device *dev;
+       int ret;
+       void *pdata;
+       unsigned int i;
+
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev) {
+               dev_err(&client->dev, "out of memory\n");
+               return -ENOMEM;
+       }
+
+       mutex_init(&dev->input_lock);
+
+       dev->fmt_idx = 0;
+       v4l2_i2c_subdev_init(&(dev->sd), client, &ov2680_ops);
+
+       if (ACPI_COMPANION(&client->dev))
+               pdata = gmin_camera_platform_data(&dev->sd,
+                                                 ATOMISP_INPUT_FORMAT_RAW_10,
+                                                 atomisp_bayer_order_bggr);
+       else
+               pdata = client->dev.platform_data;
+
+       if (!pdata) {
+               ret = -EINVAL;
+               goto out_free;
+        }
+
+       ret = ov2680_s_config(&dev->sd, client->irq, pdata);
+       if (ret)
+               goto out_free;
+
+       ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA);
+       if (ret)
+               goto out_free;
+
+       dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+       dev->pad.flags = MEDIA_PAD_FL_SOURCE;
+       dev->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
+       dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+       ret =
+           v4l2_ctrl_handler_init(&dev->ctrl_handler,
+                                  ARRAY_SIZE(ov2680_controls));
+       if (ret) {
+               ov2680_remove(client);
+               return ret;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(ov2680_controls); i++)
+               v4l2_ctrl_new_custom(&dev->ctrl_handler, &ov2680_controls[i],
+                                    NULL);
+
+       if (dev->ctrl_handler.error) {
+               ov2680_remove(client);
+               return dev->ctrl_handler.error;
+       }
+
+       /* Use same lock for controls as for everything else. */
+       dev->ctrl_handler.lock = &dev->input_lock;
+       dev->sd.ctrl_handler = &dev->ctrl_handler;
+
+       ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad);
+       if (ret)
+       {
+               ov2680_remove(client);
+               dev_dbg(&client->dev, "+++ remove ov2680 \n");
+       }
+       return ret;
+out_free:
+       dev_dbg(&client->dev, "+++ out free \n");
+       v4l2_device_unregister_subdev(&dev->sd);
+       kfree(dev);
+       return ret;
+}
+
+static const struct acpi_device_id ov2680_acpi_match[] = {
+       {"XXOV2680"},
+       {"OVTI2680"},
+       {},
+};
+MODULE_DEVICE_TABLE(acpi, ov2680_acpi_match);
+
+
+MODULE_DEVICE_TABLE(i2c, ov2680_id);
+static struct i2c_driver ov2680_driver = {
+       .driver = {
+               .owner = THIS_MODULE,
+               .name = OV2680_NAME,
+               .acpi_match_table = ACPI_PTR(ov2680_acpi_match),
+
+       },
+       .probe = ov2680_probe,
+       .remove = ov2680_remove,
+       .id_table = ov2680_id,
+};
+
+static int init_ov2680(void)
+{
+       return i2c_add_driver(&ov2680_driver);
+}
+
+static void exit_ov2680(void)
+{
+
+       i2c_del_driver(&ov2680_driver);
+}
+
+module_init(init_ov2680);
+module_exit(exit_ov2680);
+
+MODULE_AUTHOR("Jacky Wang <Jacky_wang@ovt.com>");
+MODULE_DESCRIPTION("A low-level driver for OmniVision 2680 sensors");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c
new file mode 100644 (file)
index 0000000..10094ac
--- /dev/null
@@ -0,0 +1,1373 @@
+/*
+ * Support for OmniVision OV2722 1080p HD camera sensor.
+ *
+ * Copyright (c) 2013 Intel Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kmod.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/moduleparam.h>
+#include <media/v4l2-device.h>
+#include "../include/linux/atomisp_gmin_platform.h"
+#include <linux/acpi.h>
+#include <linux/io.h>
+
+#include "ov2722.h"
+
+/* i2c read/write stuff */
+static int ov2722_read_reg(struct i2c_client *client,
+                          u16 data_length, u16 reg, u16 *val)
+{
+       int err;
+       struct i2c_msg msg[2];
+       unsigned char data[6];
+
+       if (!client->adapter) {
+               dev_err(&client->dev, "%s error, no client->adapter\n",
+                       __func__);
+               return -ENODEV;
+       }
+
+       if (data_length != OV2722_8BIT && data_length != OV2722_16BIT
+                                       && data_length != OV2722_32BIT) {
+               dev_err(&client->dev, "%s error, invalid data length\n",
+                       __func__);
+               return -EINVAL;
+       }
+
+       memset(msg, 0 , sizeof(msg));
+
+       msg[0].addr = client->addr;
+       msg[0].flags = 0;
+       msg[0].len = I2C_MSG_LENGTH;
+       msg[0].buf = data;
+
+       /* high byte goes out first */
+       data[0] = (u8)(reg >> 8);
+       data[1] = (u8)(reg & 0xff);
+
+       msg[1].addr = client->addr;
+       msg[1].len = data_length;
+       msg[1].flags = I2C_M_RD;
+       msg[1].buf = data;
+
+       err = i2c_transfer(client->adapter, msg, 2);
+       if (err != 2) {
+               if (err >= 0)
+                       err = -EIO;
+               dev_err(&client->dev,
+                       "read from offset 0x%x error %d", reg, err);
+               return err;
+       }
+
+       *val = 0;
+       /* high byte comes first */
+       if (data_length == OV2722_8BIT)
+               *val = (u8)data[0];
+       else if (data_length == OV2722_16BIT)
+               *val = be16_to_cpu(*(u16 *)&data[0]);
+       else
+               *val = be32_to_cpu(*(u32 *)&data[0]);
+
+       return 0;
+}
+
+static int ov2722_i2c_write(struct i2c_client *client, u16 len, u8 *data)
+{
+       struct i2c_msg msg;
+       const int num_msg = 1;
+       int ret;
+
+       msg.addr = client->addr;
+       msg.flags = 0;
+       msg.len = len;
+       msg.buf = data;
+       ret = i2c_transfer(client->adapter, &msg, 1);
+
+       return ret == num_msg ? 0 : -EIO;
+}
+
+static int ov2722_write_reg(struct i2c_client *client, u16 data_length,
+                                                       u16 reg, u16 val)
+{
+       int ret;
+       unsigned char data[4] = {0};
+       u16 *wreg = (u16 *)data;
+       const u16 len = data_length + sizeof(u16); /* 16-bit address + data */
+
+       if (data_length != OV2722_8BIT && data_length != OV2722_16BIT) {
+               dev_err(&client->dev,
+                       "%s error, invalid data_length\n", __func__);
+               return -EINVAL;
+       }
+
+       /* high byte goes out first */
+       *wreg = cpu_to_be16(reg);
+
+       if (data_length == OV2722_8BIT) {
+               data[2] = (u8)(val);
+       } else {
+               /* OV2722_16BIT */
+               u16 *wdata = (u16 *)&data[2];
+               *wdata = cpu_to_be16(val);
+       }
+
+       ret = ov2722_i2c_write(client, len, data);
+       if (ret)
+               dev_err(&client->dev,
+                       "write error: wrote 0x%x to offset 0x%x error %d",
+                       val, reg, ret);
+
+       return ret;
+}
+
+/*
+ * ov2722_write_reg_array - Initializes a list of OV2722 registers
+ * @client: i2c driver client structure
+ * @reglist: list of registers to be written
+ *
+ * This function initializes a list of registers. When consecutive addresses
+ * are found in a row on the list, this function creates a buffer and sends
+ * consecutive data in a single i2c_transfer().
+ *
+ * __ov2722_flush_reg_array, __ov2722_buf_reg_array() and
+ * __ov2722_write_reg_is_consecutive() are internal functions to
+ * ov2722_write_reg_array_fast() and should be not used anywhere else.
+ *
+ */
+
+static int __ov2722_flush_reg_array(struct i2c_client *client,
+                                   struct ov2722_write_ctrl *ctrl)
+{
+       u16 size;
+
+       if (ctrl->index == 0)
+               return 0;
+
+       size = sizeof(u16) + ctrl->index; /* 16-bit address + data */
+       ctrl->buffer.addr = cpu_to_be16(ctrl->buffer.addr);
+       ctrl->index = 0;
+
+       return ov2722_i2c_write(client, size, (u8 *)&ctrl->buffer);
+}
+
+static int __ov2722_buf_reg_array(struct i2c_client *client,
+                                 struct ov2722_write_ctrl *ctrl,
+                                 const struct ov2722_reg *next)
+{
+       int size;
+       u16 *data16;
+
+       switch (next->type) {
+       case OV2722_8BIT:
+               size = 1;
+               ctrl->buffer.data[ctrl->index] = (u8)next->val;
+               break;
+       case OV2722_16BIT:
+               size = 2;
+               data16 = (u16 *)&ctrl->buffer.data[ctrl->index];
+               *data16 = cpu_to_be16((u16)next->val);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* When first item is added, we need to store its starting address */
+       if (ctrl->index == 0)
+               ctrl->buffer.addr = next->reg;
+
+       ctrl->index += size;
+
+       /*
+        * Buffer cannot guarantee free space for u32? Better flush it to avoid
+        * possible lack of memory for next item.
+        */
+       if (ctrl->index + sizeof(u16) >= OV2722_MAX_WRITE_BUF_SIZE)
+               return __ov2722_flush_reg_array(client, ctrl);
+
+       return 0;
+}
+
+static int __ov2722_write_reg_is_consecutive(struct i2c_client *client,
+                                            struct ov2722_write_ctrl *ctrl,
+                                            const struct ov2722_reg *next)
+{
+       if (ctrl->index == 0)
+               return 1;
+
+       return ctrl->buffer.addr + ctrl->index == next->reg;
+}
+
+static int ov2722_write_reg_array(struct i2c_client *client,
+                                 const struct ov2722_reg *reglist)
+{
+       const struct ov2722_reg *next = reglist;
+       struct ov2722_write_ctrl ctrl;
+       int err;
+
+       ctrl.index = 0;
+       for (; next->type != OV2722_TOK_TERM; next++) {
+               switch (next->type & OV2722_TOK_MASK) {
+               case OV2722_TOK_DELAY:
+                       err = __ov2722_flush_reg_array(client, &ctrl);
+                       if (err)
+                               return err;
+                       msleep(next->val);
+                       break;
+               default:
+                       /*
+                        * If next address is not consecutive, data needs to be
+                        * flushed before proceed.
+                        */
+                       if (!__ov2722_write_reg_is_consecutive(client, &ctrl,
+                                                               next)) {
+                               err = __ov2722_flush_reg_array(client, &ctrl);
+                               if (err)
+                                       return err;
+                       }
+                       err = __ov2722_buf_reg_array(client, &ctrl, next);
+                       if (err) {
+                               dev_err(&client->dev, "%s: write error, aborted\n",
+                                        __func__);
+                               return err;
+                       }
+                       break;
+               }
+       }
+
+       return __ov2722_flush_reg_array(client, &ctrl);
+}
+static int ov2722_g_focal(struct v4l2_subdev *sd, s32 *val)
+{
+       *val = (OV2722_FOCAL_LENGTH_NUM << 16) | OV2722_FOCAL_LENGTH_DEM;
+       return 0;
+}
+
+static int ov2722_g_fnumber(struct v4l2_subdev *sd, s32 *val)
+{
+       /*const f number for imx*/
+       *val = (OV2722_F_NUMBER_DEFAULT_NUM << 16) | OV2722_F_NUMBER_DEM;
+       return 0;
+}
+
+static int ov2722_g_fnumber_range(struct v4l2_subdev *sd, s32 *val)
+{
+       *val = (OV2722_F_NUMBER_DEFAULT_NUM << 24) |
+               (OV2722_F_NUMBER_DEM << 16) |
+               (OV2722_F_NUMBER_DEFAULT_NUM << 8) | OV2722_F_NUMBER_DEM;
+       return 0;
+}
+
+static int ov2722_get_intg_factor(struct i2c_client *client,
+                               struct camera_mipi_info *info,
+                               const struct ov2722_resolution *res)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct ov2722_device *dev = NULL;
+       struct atomisp_sensor_mode_data *buf = &info->data;
+       const unsigned int ext_clk_freq_hz = 19200000;
+       const unsigned int pll_invariant_div = 10;
+       unsigned int pix_clk_freq_hz;
+       u16 pre_pll_clk_div;
+       u16 pll_multiplier;
+       u16 op_pix_clk_div;
+       u16 reg_val;
+       int ret;
+
+       if (!info)
+               return -EINVAL;
+
+       dev = to_ov2722_sensor(sd);
+
+       /* pixel clock calculattion */
+       ret =  ov2722_read_reg(client, OV2722_8BIT,
+                               OV2722_SC_CMMN_PLL_CTRL3, &pre_pll_clk_div);
+       if (ret)
+               return ret;
+
+       ret =  ov2722_read_reg(client, OV2722_8BIT,
+                               OV2722_SC_CMMN_PLL_MULTIPLIER, &pll_multiplier);
+       if (ret)
+               return ret;
+
+       ret =  ov2722_read_reg(client, OV2722_8BIT,
+                               OV2722_SC_CMMN_PLL_DEBUG_OPT, &op_pix_clk_div);
+       if (ret)
+               return ret;
+
+       pre_pll_clk_div = (pre_pll_clk_div & 0x70) >> 4;
+       if (0 == pre_pll_clk_div)
+               return -EINVAL;
+
+       pll_multiplier = pll_multiplier & 0x7f;
+       op_pix_clk_div = op_pix_clk_div & 0x03;
+       pix_clk_freq_hz = ext_clk_freq_hz / pre_pll_clk_div * pll_multiplier
+                               * op_pix_clk_div / pll_invariant_div;
+
+       dev->vt_pix_clk_freq_mhz = pix_clk_freq_hz;
+       buf->vt_pix_clk_freq_mhz = pix_clk_freq_hz;
+
+       /* get integration time */
+       buf->coarse_integration_time_min = OV2722_COARSE_INTG_TIME_MIN;
+       buf->coarse_integration_time_max_margin =
+                                       OV2722_COARSE_INTG_TIME_MAX_MARGIN;
+
+       buf->fine_integration_time_min = OV2722_FINE_INTG_TIME_MIN;
+       buf->fine_integration_time_max_margin =
+                                       OV2722_FINE_INTG_TIME_MAX_MARGIN;
+
+       buf->fine_integration_time_def = OV2722_FINE_INTG_TIME_MIN;
+       buf->frame_length_lines = res->lines_per_frame;
+       buf->line_length_pck = res->pixels_per_line;
+       buf->read_mode = res->bin_mode;
+
+       /* get the cropping and output resolution to ISP for this mode. */
+       ret =  ov2722_read_reg(client, OV2722_16BIT,
+                                       OV2722_H_CROP_START_H, &reg_val);
+       if (ret)
+               return ret;
+       buf->crop_horizontal_start = reg_val;
+
+       ret =  ov2722_read_reg(client, OV2722_16BIT,
+                                       OV2722_V_CROP_START_H, &reg_val);
+       if (ret)
+               return ret;
+       buf->crop_vertical_start = reg_val;
+
+       ret = ov2722_read_reg(client, OV2722_16BIT,
+                                       OV2722_H_CROP_END_H, &reg_val);
+       if (ret)
+               return ret;
+       buf->crop_horizontal_end = reg_val;
+
+       ret = ov2722_read_reg(client, OV2722_16BIT,
+                                       OV2722_V_CROP_END_H, &reg_val);
+       if (ret)
+               return ret;
+       buf->crop_vertical_end = reg_val;
+
+       ret = ov2722_read_reg(client, OV2722_16BIT,
+                                       OV2722_H_OUTSIZE_H, &reg_val);
+       if (ret)
+               return ret;
+       buf->output_width = reg_val;
+
+       ret = ov2722_read_reg(client, OV2722_16BIT,
+                                       OV2722_V_OUTSIZE_H, &reg_val);
+       if (ret)
+               return ret;
+       buf->output_height = reg_val;
+
+       buf->binning_factor_x = res->bin_factor_x ?
+                                       res->bin_factor_x : 1;
+       buf->binning_factor_y = res->bin_factor_y ?
+                                       res->bin_factor_y : 1;
+       return 0;
+}
+
+static long __ov2722_set_exposure(struct v4l2_subdev *sd, int coarse_itg,
+                                int gain, int digitgain)
+
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct ov2722_device *dev = to_ov2722_sensor(sd);
+       u16 hts, vts;
+       int ret;
+
+       dev_dbg(&client->dev, "set_exposure without group hold\n");
+
+       /* clear VTS_DIFF on manual mode */
+       ret = ov2722_write_reg(client, OV2722_16BIT, OV2722_VTS_DIFF_H, 0);
+       if (ret)
+               return ret;
+
+       hts = dev->pixels_per_line;
+       vts = dev->lines_per_frame;
+
+       if ((coarse_itg + OV2722_COARSE_INTG_TIME_MAX_MARGIN) > vts)
+               vts = coarse_itg + OV2722_COARSE_INTG_TIME_MAX_MARGIN;
+
+       coarse_itg <<= 4;
+       digitgain <<= 2;
+
+       ret = ov2722_write_reg(client, OV2722_16BIT,
+                               OV2722_VTS_H, vts);
+       if (ret)
+               return ret;
+
+       ret = ov2722_write_reg(client, OV2722_16BIT,
+                               OV2722_HTS_H, hts);
+       if (ret)
+               return ret;
+
+       /* set exposure */
+       ret = ov2722_write_reg(client, OV2722_8BIT,
+                                       OV2722_AEC_PK_EXPO_L,
+                                       coarse_itg & 0xff);
+       if (ret)
+               return ret;
+
+       ret = ov2722_write_reg(client, OV2722_16BIT,
+                                       OV2722_AEC_PK_EXPO_H,
+                                       (coarse_itg >> 8) & 0xfff);
+       if (ret)
+               return ret;
+
+       /* set analog gain */
+       ret = ov2722_write_reg(client, OV2722_16BIT,
+                                       OV2722_AGC_ADJ_H, gain);
+       if (ret)
+               return ret;
+
+       /* set digital gain */
+       ret = ov2722_write_reg(client, OV2722_16BIT,
+                               OV2722_MWB_GAIN_R_H, digitgain);
+       if (ret)
+               return ret;
+
+       ret = ov2722_write_reg(client, OV2722_16BIT,
+                               OV2722_MWB_GAIN_G_H, digitgain);
+       if (ret)
+               return ret;
+
+       ret = ov2722_write_reg(client, OV2722_16BIT,
+                               OV2722_MWB_GAIN_B_H, digitgain);
+
+       return ret;
+}
+
+static int ov2722_set_exposure(struct v4l2_subdev *sd, int exposure,
+       int gain, int digitgain)
+{
+       struct ov2722_device *dev = to_ov2722_sensor(sd);
+       int ret;
+
+       mutex_lock(&dev->input_lock);
+       ret = __ov2722_set_exposure(sd, exposure, gain, digitgain);
+       mutex_unlock(&dev->input_lock);
+
+       return ret;
+}
+
+static long ov2722_s_exposure(struct v4l2_subdev *sd,
+                              struct atomisp_exposure *exposure)
+{
+       int exp = exposure->integration_time[0];
+       int gain = exposure->gain[0];
+       int digitgain = exposure->gain[1];
+
+       /* we should not accept the invalid value below. */
+       if (gain == 0) {
+               struct i2c_client *client = v4l2_get_subdevdata(sd);
+               v4l2_err(client, "%s: invalid value\n", __func__);
+               return -EINVAL;
+       }
+
+       return ov2722_set_exposure(sd, exp, gain, digitgain);
+}
+
+static long ov2722_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+
+       switch (cmd) {
+       case ATOMISP_IOC_S_EXPOSURE:
+               return ov2722_s_exposure(sd, arg);
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/* This returns the exposure time being used. This should only be used
+ * for filling in EXIF data, not for actual image processing.
+ */
+static int ov2722_q_exposure(struct v4l2_subdev *sd, s32 *value)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       u16 reg_v, reg_v2;
+       int ret;
+
+       /* get exposure */
+       ret = ov2722_read_reg(client, OV2722_8BIT,
+                                       OV2722_AEC_PK_EXPO_L,
+                                       &reg_v);
+       if (ret)
+               goto err;
+
+       ret = ov2722_read_reg(client, OV2722_8BIT,
+                                       OV2722_AEC_PK_EXPO_M,
+                                       &reg_v2);
+       if (ret)
+               goto err;
+
+       reg_v += reg_v2 << 8;
+       ret = ov2722_read_reg(client, OV2722_8BIT,
+                                       OV2722_AEC_PK_EXPO_H,
+                                       &reg_v2);
+       if (ret)
+               goto err;
+
+       *value = reg_v + (((u32)reg_v2 << 16));
+err:
+       return ret;
+}
+
+static int ov2722_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct ov2722_device *dev =
+           container_of(ctrl->handler, struct ov2722_device, ctrl_handler);
+       int ret = 0;
+       unsigned int val;
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE_ABSOLUTE:
+               ret = ov2722_q_exposure(&dev->sd, &ctrl->val);
+               break;
+       case V4L2_CID_FOCAL_ABSOLUTE:
+               ret = ov2722_g_focal(&dev->sd, &ctrl->val);
+               break;
+       case V4L2_CID_FNUMBER_ABSOLUTE:
+               ret = ov2722_g_fnumber(&dev->sd, &ctrl->val);
+               break;
+       case V4L2_CID_FNUMBER_RANGE:
+               ret = ov2722_g_fnumber_range(&dev->sd, &ctrl->val);
+               break;
+       case V4L2_CID_LINK_FREQ:
+               val = ov2722_res[dev->fmt_idx].mipi_freq;
+               if (val == 0)
+                       return -EINVAL;
+
+               ctrl->val = val * 1000; /* To Hz */
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static const struct v4l2_ctrl_ops ctrl_ops = {
+       .g_volatile_ctrl = ov2722_g_volatile_ctrl
+};
+
+struct v4l2_ctrl_config ov2722_controls[] = {
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_EXPOSURE_ABSOLUTE,
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .name = "exposure",
+        .min = 0x0,
+        .max = 0xffff,
+        .step = 0x01,
+        .def = 0x00,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_FOCAL_ABSOLUTE,
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .name = "focal length",
+        .min = OV2722_FOCAL_LENGTH_DEFAULT,
+        .max = OV2722_FOCAL_LENGTH_DEFAULT,
+        .step = 0x01,
+        .def = OV2722_FOCAL_LENGTH_DEFAULT,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_FNUMBER_ABSOLUTE,
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .name = "f-number",
+        .min = OV2722_F_NUMBER_DEFAULT,
+        .max = OV2722_F_NUMBER_DEFAULT,
+        .step = 0x01,
+        .def = OV2722_F_NUMBER_DEFAULT,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_FNUMBER_RANGE,
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .name = "f-number range",
+        .min = OV2722_F_NUMBER_RANGE,
+        .max = OV2722_F_NUMBER_RANGE,
+        .step = 0x01,
+        .def = OV2722_F_NUMBER_RANGE,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_LINK_FREQ,
+        .name = "Link Frequency",
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .min = 1,
+        .max = 1500000 * 1000,
+        .step = 1,
+        .def = 1,
+        .flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
+        },
+};
+
+static int ov2722_init(struct v4l2_subdev *sd)
+{
+       struct ov2722_device *dev = to_ov2722_sensor(sd);
+
+       mutex_lock(&dev->input_lock);
+
+       /* restore settings */
+       ov2722_res = ov2722_res_preview;
+       N_RES = N_RES_PREVIEW;
+
+       mutex_unlock(&dev->input_lock);
+
+       return 0;
+}
+
+static int power_ctrl(struct v4l2_subdev *sd, bool flag)
+{
+       int ret = -1;
+       struct ov2722_device *dev = to_ov2722_sensor(sd);
+
+       if (!dev || !dev->platform_data)
+               return -ENODEV;
+
+       /* Non-gmin platforms use the legacy callback */
+       if (dev->platform_data->power_ctrl)
+               return dev->platform_data->power_ctrl(sd, flag);
+
+       if (flag) {
+               ret = dev->platform_data->v1p8_ctrl(sd, 1);
+               if (ret == 0) {
+                       ret = dev->platform_data->v2p8_ctrl(sd, 1);
+                       if (ret)
+                               dev->platform_data->v1p8_ctrl(sd, 0);
+               }
+       } else {
+               ret = dev->platform_data->v1p8_ctrl(sd, 0);
+               ret |= dev->platform_data->v2p8_ctrl(sd, 0);
+       }
+
+       return ret;
+}
+
+static int gpio_ctrl(struct v4l2_subdev *sd, bool flag)
+{
+       struct ov2722_device *dev = to_ov2722_sensor(sd);
+       int ret = -1;
+
+       if (!dev || !dev->platform_data)
+               return -ENODEV;
+
+       /* Non-gmin platforms use the legacy callback */
+       if (dev->platform_data->gpio_ctrl)
+               return dev->platform_data->gpio_ctrl(sd, flag);
+
+       /* Note: the GPIO order is asymmetric: always RESET#
+        * before PWDN# when turning it on or off.
+        */
+       ret = dev->platform_data->gpio0_ctrl(sd, flag);
+       /*
+        *ov2722 PWDN# active high when pull down,opposite to the convention
+        */
+       ret |= dev->platform_data->gpio1_ctrl(sd, !flag);
+       return ret;
+}
+
+static int power_up(struct v4l2_subdev *sd)
+{
+       struct ov2722_device *dev = to_ov2722_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret;
+
+       if (!dev->platform_data) {
+               dev_err(&client->dev,
+                       "no camera_sensor_platform_data");
+               return -ENODEV;
+       }
+
+       /* power control */
+       ret = power_ctrl(sd, 1);
+       if (ret)
+               goto fail_power;
+
+       /* according to DS, at least 5ms is needed between DOVDD and PWDN */
+       usleep_range(5000, 6000);
+
+       /* gpio ctrl */
+       ret = gpio_ctrl(sd, 1);
+       if (ret) {
+               ret = gpio_ctrl(sd, 0);
+               if (ret)
+                       goto fail_power;
+       }
+
+       /* flis clock control */
+       ret = dev->platform_data->flisclk_ctrl(sd, 1);
+       if (ret)
+               goto fail_clk;
+
+       /* according to DS, 20ms is needed between PWDN and i2c access */
+       msleep(20);
+
+       return 0;
+
+fail_clk:
+       gpio_ctrl(sd, 0);
+fail_power:
+       power_ctrl(sd, 0);
+       dev_err(&client->dev, "sensor power-up failed\n");
+
+       return ret;
+}
+
+static int power_down(struct v4l2_subdev *sd)
+{
+       struct ov2722_device *dev = to_ov2722_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret = 0;
+
+       if (!dev->platform_data) {
+               dev_err(&client->dev,
+                       "no camera_sensor_platform_data");
+               return -ENODEV;
+       }
+
+       ret = dev->platform_data->flisclk_ctrl(sd, 0);
+       if (ret)
+               dev_err(&client->dev, "flisclk failed\n");
+
+       /* gpio ctrl */
+       ret = gpio_ctrl(sd, 0);
+       if (ret) {
+               ret = gpio_ctrl(sd, 0);
+               if (ret)
+                       dev_err(&client->dev, "gpio failed 2\n");
+       }
+
+       /* power control */
+       ret = power_ctrl(sd, 0);
+       if (ret)
+               dev_err(&client->dev, "vprog failed.\n");
+
+       return ret;
+}
+
+static int ov2722_s_power(struct v4l2_subdev *sd, int on)
+{
+       int ret;
+       if (on == 0)
+               return power_down(sd);
+       else {
+               ret = power_up(sd);
+               if (!ret)
+                       return ov2722_init(sd);
+       }
+       return ret;
+}
+
+/*
+ * distance - calculate the distance
+ * @res: resolution
+ * @w: width
+ * @h: height
+ *
+ * Get the gap between resolution and w/h.
+ * res->width/height smaller than w/h wouldn't be considered.
+ * Returns the value of gap or -1 if fail.
+ */
+#define LARGEST_ALLOWED_RATIO_MISMATCH 800
+static int distance(struct ov2722_resolution *res, u32 w, u32 h)
+{
+       unsigned int w_ratio = (res->width << 13) / w;
+       unsigned int h_ratio;
+       int match;
+
+       if (h == 0)
+               return -1;
+       h_ratio = (res->height << 13) / h;
+       if (h_ratio == 0)
+               return -1;
+       match   = abs(((w_ratio << 13) / h_ratio) - 8192);
+
+       if ((w_ratio < 8192) || (h_ratio < 8192) ||
+           (match > LARGEST_ALLOWED_RATIO_MISMATCH))
+               return -1;
+
+       return w_ratio + h_ratio;
+}
+
+/* Return the nearest higher resolution index */
+static int nearest_resolution_index(int w, int h)
+{
+       int i;
+       int idx = -1;
+       int dist;
+       int min_dist = INT_MAX;
+       struct ov2722_resolution *tmp_res = NULL;
+
+       for (i = 0; i < N_RES; i++) {
+               tmp_res = &ov2722_res[i];
+               dist = distance(tmp_res, w, h);
+               if (dist == -1)
+                       continue;
+               if (dist < min_dist) {
+                       min_dist = dist;
+                       idx = i;
+               }
+       }
+
+       return idx;
+}
+
+static int get_resolution_index(int w, int h)
+{
+       int i;
+
+       for (i = 0; i < N_RES; i++) {
+               if (w != ov2722_res[i].width)
+                       continue;
+               if (h != ov2722_res[i].height)
+                       continue;
+
+               return i;
+       }
+
+       return -1;
+}
+
+/* TODO: remove it. */
+static int startup(struct v4l2_subdev *sd)
+{
+       struct ov2722_device *dev = to_ov2722_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret = 0;
+
+       ret = ov2722_write_reg(client, OV2722_8BIT,
+                                       OV2722_SW_RESET, 0x01);
+       if (ret) {
+               dev_err(&client->dev, "ov2722 reset err.\n");
+               return ret;
+       }
+
+       ret = ov2722_write_reg_array(client, ov2722_res[dev->fmt_idx].regs);
+       if (ret) {
+               dev_err(&client->dev, "ov2722 write register err.\n");
+               return ret;
+       }
+
+       return ret;
+}
+
+static int ov2722_set_fmt(struct v4l2_subdev *sd,
+                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_format *format)
+{
+       struct v4l2_mbus_framefmt *fmt = &format->format;
+       struct ov2722_device *dev = to_ov2722_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct camera_mipi_info *ov2722_info = NULL;
+       int ret = 0;
+       int idx;
+       if (format->pad)
+               return -EINVAL;
+       if (!fmt)
+               return -EINVAL;
+       ov2722_info = v4l2_get_subdev_hostdata(sd);
+       if (!ov2722_info)
+               return -EINVAL;
+
+       mutex_lock(&dev->input_lock);
+       idx = nearest_resolution_index(fmt->width, fmt->height);
+       if (idx == -1) {
+               /* return the largest resolution */
+               fmt->width = ov2722_res[N_RES - 1].width;
+               fmt->height = ov2722_res[N_RES - 1].height;
+       } else {
+               fmt->width = ov2722_res[idx].width;
+               fmt->height = ov2722_res[idx].height;
+       }
+       fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
+       if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+               cfg->try_fmt = *fmt;
+               mutex_unlock(&dev->input_lock);
+               return 0;
+       }
+
+       dev->fmt_idx = get_resolution_index(fmt->width, fmt->height);
+       if (dev->fmt_idx == -1) {
+               dev_err(&client->dev, "get resolution fail\n");
+               mutex_unlock(&dev->input_lock);
+               return -EINVAL;
+       }
+
+       dev->pixels_per_line = ov2722_res[dev->fmt_idx].pixels_per_line;
+       dev->lines_per_frame = ov2722_res[dev->fmt_idx].lines_per_frame;
+
+       ret = startup(sd);
+       if (ret) {
+               int i = 0;
+               dev_err(&client->dev, "ov2722 startup err, retry to power up\n");
+               for (i = 0; i < OV2722_POWER_UP_RETRY_NUM; i++) {
+                       dev_err(&client->dev,
+                               "ov2722 retry to power up %d/%d times, result: ",
+                               i + 1, OV2722_POWER_UP_RETRY_NUM);
+                       power_down(sd);
+                       ret = power_up(sd);
+                       if (ret) {
+                               dev_err(&client->dev, "power up failed, continue\n");
+                               continue;
+                       }
+                       ret = startup(sd);
+                       if (ret) {
+                               dev_err(&client->dev, " startup FAILED!\n");
+                       } else {
+                               dev_err(&client->dev, " startup SUCCESS!\n");
+                               break;
+                       }
+               }
+               if (ret) {
+                       dev_err(&client->dev, "ov2722 startup err\n");
+                       goto err;
+               }
+       }
+
+       ret = ov2722_get_intg_factor(client, ov2722_info,
+                                       &ov2722_res[dev->fmt_idx]);
+       if (ret)
+               dev_err(&client->dev, "failed to get integration_factor\n");
+
+err:
+       mutex_unlock(&dev->input_lock);
+       return ret;
+}
+static int ov2722_get_fmt(struct v4l2_subdev *sd,
+                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_format *format)
+{
+       struct v4l2_mbus_framefmt *fmt = &format->format;
+       struct ov2722_device *dev = to_ov2722_sensor(sd);
+
+       if (format->pad)
+               return -EINVAL;
+       if (!fmt)
+               return -EINVAL;
+
+       fmt->width = ov2722_res[dev->fmt_idx].width;
+       fmt->height = ov2722_res[dev->fmt_idx].height;
+       fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
+
+       return 0;
+}
+
+static int ov2722_detect(struct i2c_client *client)
+{
+       struct i2c_adapter *adapter = client->adapter;
+       u16 high, low;
+       int ret;
+       u16 id;
+       u8 revision;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
+               return -ENODEV;
+
+       ret = ov2722_read_reg(client, OV2722_8BIT,
+                                       OV2722_SC_CMMN_CHIP_ID_H, &high);
+       if (ret) {
+               dev_err(&client->dev, "sensor_id_high = 0x%x\n", high);
+               return -ENODEV;
+       }
+       ret = ov2722_read_reg(client, OV2722_8BIT,
+                                       OV2722_SC_CMMN_CHIP_ID_L, &low);
+       id = (high << 8) | low;
+
+       if ((id != OV2722_ID) && (id != OV2720_ID)) {
+               dev_err(&client->dev, "sensor ID error\n");
+               return -ENODEV;
+       }
+
+       ret = ov2722_read_reg(client, OV2722_8BIT,
+                                       OV2722_SC_CMMN_SUB_ID, &high);
+       revision = (u8) high & 0x0f;
+
+       dev_dbg(&client->dev, "sensor_revision = 0x%x\n", revision);
+       dev_dbg(&client->dev, "detect ov2722 success\n");
+       return 0;
+}
+
+static int ov2722_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct ov2722_device *dev = to_ov2722_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret;
+
+       mutex_lock(&dev->input_lock);
+
+       ret = ov2722_write_reg(client, OV2722_8BIT, OV2722_SW_STREAM,
+                               enable ? OV2722_START_STREAMING :
+                               OV2722_STOP_STREAMING);
+
+       mutex_unlock(&dev->input_lock);
+       return ret;
+}
+
+static int ov2722_s_config(struct v4l2_subdev *sd,
+                          int irq, void *platform_data)
+{
+       struct ov2722_device *dev = to_ov2722_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret = 0;
+
+       if (!platform_data)
+               return -ENODEV;
+
+       dev->platform_data =
+               (struct camera_sensor_platform_data *)platform_data;
+
+       mutex_lock(&dev->input_lock);
+       if (dev->platform_data->platform_init) {
+               ret = dev->platform_data->platform_init(client);
+               if (ret) {
+                       dev_err(&client->dev, "platform init err\n");
+                       goto platform_init_failed;
+               }
+       }
+
+       /* power off the module, then power on it in future
+        * as first power on by board may not fulfill the
+        * power on sequqence needed by the module
+        */
+       ret = power_down(sd);
+       if (ret) {
+               dev_err(&client->dev, "ov2722 power-off err.\n");
+               goto fail_power_off;
+       }
+
+       ret = power_up(sd);
+       if (ret) {
+               dev_err(&client->dev, "ov2722 power-up err.\n");
+               goto fail_power_on;
+       }
+
+       ret = dev->platform_data->csi_cfg(sd, 1);
+       if (ret)
+               goto fail_csi_cfg;
+
+       /* config & detect sensor */
+       ret = ov2722_detect(client);
+       if (ret) {
+               dev_err(&client->dev, "ov2722_detect err s_config.\n");
+               goto fail_csi_cfg;
+       }
+
+       /* turn off sensor, after probed */
+       ret = power_down(sd);
+       if (ret) {
+               dev_err(&client->dev, "ov2722 power-off err.\n");
+               goto fail_csi_cfg;
+       }
+       mutex_unlock(&dev->input_lock);
+
+       return 0;
+
+fail_csi_cfg:
+       dev->platform_data->csi_cfg(sd, 0);
+fail_power_on:
+       power_down(sd);
+       dev_err(&client->dev, "sensor power-gating failed\n");
+fail_power_off:
+       if (dev->platform_data->platform_deinit)
+               dev->platform_data->platform_deinit();
+platform_init_failed:
+       mutex_unlock(&dev->input_lock);
+       return ret;
+}
+
+static int ov2722_g_parm(struct v4l2_subdev *sd,
+                       struct v4l2_streamparm *param)
+{
+       struct ov2722_device *dev = to_ov2722_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (!param)
+               return -EINVAL;
+
+       if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               dev_err(&client->dev,  "unsupported buffer type.\n");
+               return -EINVAL;
+       }
+
+       memset(param, 0, sizeof(*param));
+       param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+       if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) {
+               param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+               param->parm.capture.timeperframe.numerator = 1;
+               param->parm.capture.capturemode = dev->run_mode;
+               param->parm.capture.timeperframe.denominator =
+                       ov2722_res[dev->fmt_idx].fps;
+       }
+       return 0;
+}
+
+static int ov2722_s_parm(struct v4l2_subdev *sd,
+                       struct v4l2_streamparm *param)
+{
+       struct ov2722_device *dev = to_ov2722_sensor(sd);
+       dev->run_mode = param->parm.capture.capturemode;
+
+       mutex_lock(&dev->input_lock);
+       switch (dev->run_mode) {
+       case CI_MODE_VIDEO:
+               ov2722_res = ov2722_res_video;
+               N_RES = N_RES_VIDEO;
+               break;
+       case CI_MODE_STILL_CAPTURE:
+               ov2722_res = ov2722_res_still;
+               N_RES = N_RES_STILL;
+               break;
+       default:
+               ov2722_res = ov2722_res_preview;
+               N_RES = N_RES_PREVIEW;
+       }
+       mutex_unlock(&dev->input_lock);
+       return 0;
+}
+
+static int ov2722_g_frame_interval(struct v4l2_subdev *sd,
+                                  struct v4l2_subdev_frame_interval *interval)
+{
+       struct ov2722_device *dev = to_ov2722_sensor(sd);
+
+       interval->interval.numerator = 1;
+       interval->interval.denominator = ov2722_res[dev->fmt_idx].fps;
+
+       return 0;
+}
+
+static int ov2722_enum_mbus_code(struct v4l2_subdev *sd,
+                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_mbus_code_enum *code)
+{
+       if (code->index >= MAX_FMTS)
+               return -EINVAL;
+
+       code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
+       return 0;
+}
+
+static int ov2722_enum_frame_size(struct v4l2_subdev *sd,
+                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_frame_size_enum *fse)
+{
+       int index = fse->index;
+
+       if (index >= N_RES)
+               return -EINVAL;
+
+       fse->min_width = ov2722_res[index].width;
+       fse->min_height = ov2722_res[index].height;
+       fse->max_width = ov2722_res[index].width;
+       fse->max_height = ov2722_res[index].height;
+
+       return 0;
+
+}
+
+
+static int ov2722_g_skip_frames(struct v4l2_subdev *sd, u32 *frames)
+{
+       struct ov2722_device *dev = to_ov2722_sensor(sd);
+
+       mutex_lock(&dev->input_lock);
+       *frames = ov2722_res[dev->fmt_idx].skip_frames;
+       mutex_unlock(&dev->input_lock);
+
+       return 0;
+}
+
+static const struct v4l2_subdev_sensor_ops ov2722_sensor_ops = {
+       .g_skip_frames  = ov2722_g_skip_frames,
+};
+
+static const struct v4l2_subdev_video_ops ov2722_video_ops = {
+       .s_stream = ov2722_s_stream,
+       .g_parm = ov2722_g_parm,
+       .s_parm = ov2722_s_parm,
+       .g_frame_interval = ov2722_g_frame_interval,
+};
+
+static const struct v4l2_subdev_core_ops ov2722_core_ops = {
+       .s_power = ov2722_s_power,
+       .ioctl = ov2722_ioctl,
+};
+
+static const struct v4l2_subdev_pad_ops ov2722_pad_ops = {
+       .enum_mbus_code = ov2722_enum_mbus_code,
+       .enum_frame_size = ov2722_enum_frame_size,
+       .get_fmt = ov2722_get_fmt,
+       .set_fmt = ov2722_set_fmt,
+};
+
+static const struct v4l2_subdev_ops ov2722_ops = {
+       .core = &ov2722_core_ops,
+       .video = &ov2722_video_ops,
+       .pad = &ov2722_pad_ops,
+       .sensor = &ov2722_sensor_ops,
+};
+
+static int ov2722_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct ov2722_device *dev = to_ov2722_sensor(sd);
+       dev_dbg(&client->dev, "ov2722_remove...\n");
+
+       if (dev->platform_data->platform_deinit)
+               dev->platform_data->platform_deinit();
+
+       dev->platform_data->csi_cfg(sd, 0);
+       v4l2_ctrl_handler_free(&dev->ctrl_handler);
+       v4l2_device_unregister_subdev(sd);
+
+       atomisp_gmin_remove_subdev(sd);
+
+       media_entity_cleanup(&dev->sd.entity);
+       kfree(dev);
+
+       return 0;
+}
+
+static int __ov2722_init_ctrl_handler(struct ov2722_device *dev)
+{
+       struct v4l2_ctrl_handler *hdl;
+       unsigned int i;
+       hdl = &dev->ctrl_handler;
+       v4l2_ctrl_handler_init(&dev->ctrl_handler, ARRAY_SIZE(ov2722_controls));
+       for (i = 0; i < ARRAY_SIZE(ov2722_controls); i++)
+               v4l2_ctrl_new_custom(&dev->ctrl_handler, &ov2722_controls[i],
+                                    NULL);
+
+       dev->link_freq = v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_LINK_FREQ);
+
+       if (dev->ctrl_handler.error || !dev->link_freq)
+               return dev->ctrl_handler.error;
+
+       dev->sd.ctrl_handler = hdl;
+
+       return 0;
+}
+
+static int ov2722_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct ov2722_device *dev;
+       void *ovpdev;
+       int ret;
+       struct acpi_device *adev;
+
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev) {
+               dev_err(&client->dev, "out of memory\n");
+               return -ENOMEM;
+       }
+
+       mutex_init(&dev->input_lock);
+
+       dev->fmt_idx = 0;
+       v4l2_i2c_subdev_init(&(dev->sd), client, &ov2722_ops);
+
+       ovpdev = client->dev.platform_data;
+       adev = ACPI_COMPANION(&client->dev);
+       if (adev) {
+               adev->power.flags.power_resources = 0;
+               ovpdev = gmin_camera_platform_data(&dev->sd,
+                                                  ATOMISP_INPUT_FORMAT_RAW_10,
+                                                  atomisp_bayer_order_grbg);
+       }
+
+       ret = ov2722_s_config(&dev->sd, client->irq, ovpdev);
+       if (ret)
+               goto out_free;
+
+       ret = __ov2722_init_ctrl_handler(dev);
+       if (ret)
+               goto out_ctrl_handler_free;
+
+       dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+       dev->pad.flags = MEDIA_PAD_FL_SOURCE;
+       dev->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
+       dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+
+       ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad);
+       if (ret)
+               ov2722_remove(client);
+
+       if (ACPI_HANDLE(&client->dev))
+               ret = atomisp_register_i2c_module(&dev->sd, ovpdev, RAW_CAMERA);
+
+       return ret;
+
+out_ctrl_handler_free:
+       v4l2_ctrl_handler_free(&dev->ctrl_handler);
+
+out_free:
+       v4l2_device_unregister_subdev(&dev->sd);
+       kfree(dev);
+       return ret;
+}
+
+MODULE_DEVICE_TABLE(i2c, ov2722_id);
+
+static const struct acpi_device_id ov2722_acpi_match[] = {
+       { "INT33FB" },
+       {},
+};
+
+MODULE_DEVICE_TABLE(acpi, ov2722_acpi_match);
+
+static struct i2c_driver ov2722_driver = {
+       .driver = {
+               .name = OV2722_NAME,
+               .acpi_match_table = ACPI_PTR(ov2722_acpi_match),
+       },
+       .probe = ov2722_probe,
+       .remove = ov2722_remove,
+       .id_table = ov2722_id,
+};
+
+static int init_ov2722(void)
+{
+       return i2c_add_driver(&ov2722_driver);
+}
+
+static void exit_ov2722(void)
+{
+
+       i2c_del_driver(&ov2722_driver);
+}
+
+module_init(init_ov2722);
+module_exit(exit_ov2722);
+
+MODULE_AUTHOR("Wei Liu <wei.liu@intel.com>");
+MODULE_DESCRIPTION("A low-level driver for OmniVision 2722 sensors");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/media/atomisp/i2c/gc0310.c b/drivers/staging/media/atomisp/i2c/gc0310.c
deleted file mode 100644 (file)
index 35ed51f..0000000
+++ /dev/null
@@ -1,1490 +0,0 @@
-/*
- * Support for GalaxyCore GC0310 VGA camera sensor.
- *
- * Copyright (c) 2013 Intel Corporation. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/kmod.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/gpio.h>
-#include <linux/moduleparam.h>
-#include <media/v4l2-device.h>
-#include <linux/io.h>
-#include "../include/linux/atomisp_gmin_platform.h"
-
-#include "gc0310.h"
-
-/* i2c read/write stuff */
-static int gc0310_read_reg(struct i2c_client *client,
-                          u16 data_length, u8 reg, u8 *val)
-{
-       int err;
-       struct i2c_msg msg[2];
-       unsigned char data[1];
-
-       if (!client->adapter) {
-               dev_err(&client->dev, "%s error, no client->adapter\n",
-                       __func__);
-               return -ENODEV;
-       }
-
-       if (data_length != GC0310_8BIT) {
-               dev_err(&client->dev, "%s error, invalid data length\n",
-                       __func__);
-               return -EINVAL;
-       }
-
-       memset(msg, 0, sizeof(msg));
-
-       msg[0].addr = client->addr;
-       msg[0].flags = 0;
-       msg[0].len = I2C_MSG_LENGTH;
-       msg[0].buf = data;
-
-       /* high byte goes out first */
-       data[0] = (u8)(reg & 0xff);
-
-       msg[1].addr = client->addr;
-       msg[1].len = data_length;
-       msg[1].flags = I2C_M_RD;
-       msg[1].buf = data;
-
-       err = i2c_transfer(client->adapter, msg, 2);
-       if (err != 2) {
-               if (err >= 0)
-                       err = -EIO;
-               dev_err(&client->dev,
-                       "read from offset 0x%x error %d", reg, err);
-               return err;
-       }
-
-       *val = 0;
-       /* high byte comes first */
-       if (data_length == GC0310_8BIT)
-               *val = (u8)data[0];
-
-       return 0;
-}
-
-static int gc0310_i2c_write(struct i2c_client *client, u16 len, u8 *data)
-{
-       struct i2c_msg msg;
-       const int num_msg = 1;
-       int ret;
-
-       msg.addr = client->addr;
-       msg.flags = 0;
-       msg.len = len;
-       msg.buf = data;
-       ret = i2c_transfer(client->adapter, &msg, 1);
-
-       return ret == num_msg ? 0 : -EIO;
-}
-
-static int gc0310_write_reg(struct i2c_client *client, u16 data_length,
-                                                       u8 reg, u8 val)
-{
-       int ret;
-       unsigned char data[2] = {0};
-       u8 *wreg = (u8 *)data;
-       const u16 len = data_length + sizeof(u8); /* 8-bit address + data */
-
-       if (data_length != GC0310_8BIT) {
-               dev_err(&client->dev,
-                       "%s error, invalid data_length\n", __func__);
-               return -EINVAL;
-       }
-
-       /* high byte goes out first */
-       *wreg = (u8)(reg & 0xff);
-
-       if (data_length == GC0310_8BIT)
-               data[1] = (u8)(val);
-
-       ret = gc0310_i2c_write(client, len, data);
-       if (ret)
-               dev_err(&client->dev,
-                       "write error: wrote 0x%x to offset 0x%x error %d",
-                       val, reg, ret);
-
-       return ret;
-}
-
-/*
- * gc0310_write_reg_array - Initializes a list of GC0310 registers
- * @client: i2c driver client structure
- * @reglist: list of registers to be written
- *
- * This function initializes a list of registers. When consecutive addresses
- * are found in a row on the list, this function creates a buffer and sends
- * consecutive data in a single i2c_transfer().
- *
- * __gc0310_flush_reg_array, __gc0310_buf_reg_array() and
- * __gc0310_write_reg_is_consecutive() are internal functions to
- * gc0310_write_reg_array_fast() and should be not used anywhere else.
- *
- */
-
-static int __gc0310_flush_reg_array(struct i2c_client *client,
-                                   struct gc0310_write_ctrl *ctrl)
-{
-       u16 size;
-
-       if (ctrl->index == 0)
-               return 0;
-
-       size = sizeof(u8) + ctrl->index; /* 8-bit address + data */
-       ctrl->buffer.addr = (u8)(ctrl->buffer.addr);
-       ctrl->index = 0;
-
-       return gc0310_i2c_write(client, size, (u8 *)&ctrl->buffer);
-}
-
-static int __gc0310_buf_reg_array(struct i2c_client *client,
-                                 struct gc0310_write_ctrl *ctrl,
-                                 const struct gc0310_reg *next)
-{
-       int size;
-
-       switch (next->type) {
-       case GC0310_8BIT:
-               size = 1;
-               ctrl->buffer.data[ctrl->index] = (u8)next->val;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       /* When first item is added, we need to store its starting address */
-       if (ctrl->index == 0)
-               ctrl->buffer.addr = next->reg;
-
-       ctrl->index += size;
-
-       /*
-        * Buffer cannot guarantee free space for u32? Better flush it to avoid
-        * possible lack of memory for next item.
-        */
-       if (ctrl->index + sizeof(u8) >= GC0310_MAX_WRITE_BUF_SIZE)
-               return __gc0310_flush_reg_array(client, ctrl);
-
-       return 0;
-}
-
-static int __gc0310_write_reg_is_consecutive(struct i2c_client *client,
-                                            struct gc0310_write_ctrl *ctrl,
-                                            const struct gc0310_reg *next)
-{
-       if (ctrl->index == 0)
-               return 1;
-
-       return ctrl->buffer.addr + ctrl->index == next->reg;
-}
-
-static int gc0310_write_reg_array(struct i2c_client *client,
-                                 const struct gc0310_reg *reglist)
-{
-       const struct gc0310_reg *next = reglist;
-       struct gc0310_write_ctrl ctrl;
-       int err;
-
-       ctrl.index = 0;
-       for (; next->type != GC0310_TOK_TERM; next++) {
-               switch (next->type & GC0310_TOK_MASK) {
-               case GC0310_TOK_DELAY:
-                       err = __gc0310_flush_reg_array(client, &ctrl);
-                       if (err)
-                               return err;
-                       msleep(next->val);
-                       break;
-               default:
-                       /*
-                        * If next address is not consecutive, data needs to be
-                        * flushed before proceed.
-                        */
-                       if (!__gc0310_write_reg_is_consecutive(client, &ctrl,
-                                                               next)) {
-                               err = __gc0310_flush_reg_array(client, &ctrl);
-                               if (err)
-                                       return err;
-                       }
-                       err = __gc0310_buf_reg_array(client, &ctrl, next);
-                       if (err) {
-                               dev_err(&client->dev, "%s: write error, aborted\n",
-                                        __func__);
-                               return err;
-                       }
-                       break;
-               }
-       }
-
-       return __gc0310_flush_reg_array(client, &ctrl);
-}
-static int gc0310_g_focal(struct v4l2_subdev *sd, s32 *val)
-{
-       *val = (GC0310_FOCAL_LENGTH_NUM << 16) | GC0310_FOCAL_LENGTH_DEM;
-       return 0;
-}
-
-static int gc0310_g_fnumber(struct v4l2_subdev *sd, s32 *val)
-{
-       /*const f number for imx*/
-       *val = (GC0310_F_NUMBER_DEFAULT_NUM << 16) | GC0310_F_NUMBER_DEM;
-       return 0;
-}
-
-static int gc0310_g_fnumber_range(struct v4l2_subdev *sd, s32 *val)
-{
-       *val = (GC0310_F_NUMBER_DEFAULT_NUM << 24) |
-               (GC0310_F_NUMBER_DEM << 16) |
-               (GC0310_F_NUMBER_DEFAULT_NUM << 8) | GC0310_F_NUMBER_DEM;
-       return 0;
-}
-
-static int gc0310_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val)
-{
-       struct gc0310_device *dev = to_gc0310_sensor(sd);
-
-       *val = gc0310_res[dev->fmt_idx].bin_factor_x;
-
-       return 0;
-}
-
-static int gc0310_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val)
-{
-       struct gc0310_device *dev = to_gc0310_sensor(sd);
-
-       *val = gc0310_res[dev->fmt_idx].bin_factor_y;
-
-       return 0;
-}
-
-static int gc0310_get_intg_factor(struct i2c_client *client,
-                               struct camera_mipi_info *info,
-                               const struct gc0310_resolution *res)
-{
-       struct v4l2_subdev *sd = i2c_get_clientdata(client);
-       struct gc0310_device *dev = to_gc0310_sensor(sd);
-       struct atomisp_sensor_mode_data *buf = &info->data;
-       u16 val;
-       u8 reg_val;
-       int ret;
-       unsigned int hori_blanking;
-       unsigned int vert_blanking;
-       unsigned int sh_delay;
-
-       if (!info)
-               return -EINVAL;
-
-       /* pixel clock calculattion */
-       dev->vt_pix_clk_freq_mhz = 14400000; // 16.8MHz
-       buf->vt_pix_clk_freq_mhz = dev->vt_pix_clk_freq_mhz;
-       pr_info("vt_pix_clk_freq_mhz=%d\n", buf->vt_pix_clk_freq_mhz);
-
-       /* get integration time */
-       buf->coarse_integration_time_min = GC0310_COARSE_INTG_TIME_MIN;
-       buf->coarse_integration_time_max_margin =
-                                       GC0310_COARSE_INTG_TIME_MAX_MARGIN;
-
-       buf->fine_integration_time_min = GC0310_FINE_INTG_TIME_MIN;
-       buf->fine_integration_time_max_margin =
-                                       GC0310_FINE_INTG_TIME_MAX_MARGIN;
-
-       buf->fine_integration_time_def = GC0310_FINE_INTG_TIME_MIN;
-       buf->read_mode = res->bin_mode;
-
-       /* get the cropping and output resolution to ISP for this mode. */
-       /* Getting crop_horizontal_start */
-       ret =  gc0310_read_reg(client, GC0310_8BIT,
-                                       GC0310_H_CROP_START_H, &reg_val);
-       if (ret)
-               return ret;
-       val = (reg_val & 0xFF) << 8;
-       ret =  gc0310_read_reg(client, GC0310_8BIT,
-                                       GC0310_H_CROP_START_L, &reg_val);
-       if (ret)
-               return ret;
-       buf->crop_horizontal_start = val | (reg_val & 0xFF);
-       pr_info("crop_horizontal_start=%d\n", buf->crop_horizontal_start);
-
-       /* Getting crop_vertical_start */
-       ret =  gc0310_read_reg(client, GC0310_8BIT,
-                                       GC0310_V_CROP_START_H, &reg_val);
-       if (ret)
-               return ret;
-       val = (reg_val & 0xFF) << 8;
-       ret =  gc0310_read_reg(client, GC0310_8BIT,
-                                       GC0310_V_CROP_START_L, &reg_val);
-       if (ret)
-               return ret;
-       buf->crop_vertical_start = val | (reg_val & 0xFF);
-       pr_info("crop_vertical_start=%d\n", buf->crop_vertical_start);
-
-       /* Getting output_width */
-       ret = gc0310_read_reg(client, GC0310_8BIT,
-                                       GC0310_H_OUTSIZE_H, &reg_val);
-       if (ret)
-               return ret;
-       val = (reg_val & 0xFF) << 8;
-       ret = gc0310_read_reg(client, GC0310_8BIT,
-                                       GC0310_H_OUTSIZE_L, &reg_val);
-       if (ret)
-               return ret;
-       buf->output_width = val | (reg_val & 0xFF);
-       pr_info("output_width=%d\n", buf->output_width);
-
-       /* Getting output_height */
-       ret = gc0310_read_reg(client, GC0310_8BIT,
-                                       GC0310_V_OUTSIZE_H, &reg_val);
-       if (ret)
-               return ret;
-       val = (reg_val & 0xFF) << 8;
-       ret = gc0310_read_reg(client, GC0310_8BIT,
-                                       GC0310_V_OUTSIZE_L, &reg_val);
-       if (ret)
-               return ret;
-       buf->output_height = val | (reg_val & 0xFF);
-       pr_info("output_height=%d\n", buf->output_height);
-
-       buf->crop_horizontal_end = buf->crop_horizontal_start + buf->output_width - 1;
-       buf->crop_vertical_end = buf->crop_vertical_start + buf->output_height - 1;
-       pr_info("crop_horizontal_end=%d\n", buf->crop_horizontal_end);
-       pr_info("crop_vertical_end=%d\n", buf->crop_vertical_end);
-
-       /* Getting line_length_pck */
-       ret = gc0310_read_reg(client, GC0310_8BIT,
-                                       GC0310_H_BLANKING_H, &reg_val);
-       if (ret)
-               return ret;
-       val = (reg_val & 0xFF) << 8;
-       ret = gc0310_read_reg(client, GC0310_8BIT,
-                                       GC0310_H_BLANKING_L, &reg_val);
-       if (ret)
-               return ret;
-       hori_blanking = val | (reg_val & 0xFF);
-       ret = gc0310_read_reg(client, GC0310_8BIT,
-                                       GC0310_SH_DELAY, &reg_val);
-       if (ret)
-               return ret;
-       sh_delay = reg_val;
-       buf->line_length_pck = buf->output_width + hori_blanking + sh_delay + 4;
-       pr_info("hori_blanking=%d sh_delay=%d line_length_pck=%d\n", hori_blanking, sh_delay, buf->line_length_pck);
-
-       /* Getting frame_length_lines */
-       ret = gc0310_read_reg(client, GC0310_8BIT,
-                                       GC0310_V_BLANKING_H, &reg_val);
-       if (ret)
-               return ret;
-       val = (reg_val & 0xFF) << 8;
-       ret = gc0310_read_reg(client, GC0310_8BIT,
-                                       GC0310_V_BLANKING_L, &reg_val);
-       if (ret)
-               return ret;
-       vert_blanking = val | (reg_val & 0xFF);
-       buf->frame_length_lines = buf->output_height + vert_blanking;
-       pr_info("vert_blanking=%d frame_length_lines=%d\n", vert_blanking, buf->frame_length_lines);
-
-       buf->binning_factor_x = res->bin_factor_x ?
-                                       res->bin_factor_x : 1;
-       buf->binning_factor_y = res->bin_factor_y ?
-                                       res->bin_factor_y : 1;
-       return 0;
-}
-
-static int gc0310_set_gain(struct v4l2_subdev *sd, int gain)
-
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret;
-       u8 again, dgain;
-
-       if (gain < 0x20)
-               gain = 0x20;
-       if (gain > 0x80)
-               gain = 0x80;
-
-       if (gain >= 0x20 && gain < 0x40) {
-               again = 0x0; /* sqrt(2) */
-               dgain = gain;
-       } else {
-               again = 0x2; /* 2 * sqrt(2) */
-               dgain = gain / 2;
-       }
-
-       pr_info("gain=0x%x again=0x%x dgain=0x%x\n", gain, again, dgain);
-
-       /* set analog gain */
-       ret = gc0310_write_reg(client, GC0310_8BIT,
-                                       GC0310_AGC_ADJ, again);
-       if (ret)
-               return ret;
-
-       /* set digital gain */
-       ret = gc0310_write_reg(client, GC0310_8BIT,
-                                       GC0310_DGC_ADJ, dgain);
-       if (ret)
-               return ret;
-
-       return 0;
-}
-
-static int __gc0310_set_exposure(struct v4l2_subdev *sd, int coarse_itg,
-                                int gain, int digitgain)
-
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret;
-
-       pr_info("coarse_itg=%d gain=%d digitgain=%d\n", coarse_itg, gain, digitgain);
-
-       /* set exposure */
-       ret = gc0310_write_reg(client, GC0310_8BIT,
-                                       GC0310_AEC_PK_EXPO_L,
-                                       coarse_itg & 0xff);
-       if (ret)
-               return ret;
-
-       ret = gc0310_write_reg(client, GC0310_8BIT,
-                                       GC0310_AEC_PK_EXPO_H,
-                                       (coarse_itg >> 8) & 0x0f);
-       if (ret)
-               return ret;
-
-       ret = gc0310_set_gain(sd, gain);
-       if (ret)
-               return ret;
-
-       return ret;
-}
-
-static int gc0310_set_exposure(struct v4l2_subdev *sd, int exposure,
-       int gain, int digitgain)
-{
-       struct gc0310_device *dev = to_gc0310_sensor(sd);
-       int ret;
-
-       mutex_lock(&dev->input_lock);
-       ret = __gc0310_set_exposure(sd, exposure, gain, digitgain);
-       mutex_unlock(&dev->input_lock);
-
-       return ret;
-}
-
-static long gc0310_s_exposure(struct v4l2_subdev *sd,
-                              struct atomisp_exposure *exposure)
-{
-       int exp = exposure->integration_time[0];
-       int gain = exposure->gain[0];
-       int digitgain = exposure->gain[1];
-
-       /* we should not accept the invalid value below. */
-       if (gain == 0) {
-               struct i2c_client *client = v4l2_get_subdevdata(sd);
-               v4l2_err(client, "%s: invalid value\n", __func__);
-               return -EINVAL;
-       }
-
-       return gc0310_set_exposure(sd, exp, gain, digitgain);
-}
-
-/* TO DO */
-static int gc0310_v_flip(struct v4l2_subdev *sd, s32 value)
-{
-       return 0;
-}
-
-/* TO DO */
-static int gc0310_h_flip(struct v4l2_subdev *sd, s32 value)
-{
-       return 0;
-}
-
-static long gc0310_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
-{
-
-       switch (cmd) {
-       case ATOMISP_IOC_S_EXPOSURE:
-               return gc0310_s_exposure(sd, arg);
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-
-/* This returns the exposure time being used. This should only be used
- * for filling in EXIF data, not for actual image processing.
- */
-static int gc0310_q_exposure(struct v4l2_subdev *sd, s32 *value)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       u8 reg_v;
-       int ret;
-
-       /* get exposure */
-       ret = gc0310_read_reg(client, GC0310_8BIT,
-                                       GC0310_AEC_PK_EXPO_L,
-                                       &reg_v);
-       if (ret)
-               goto err;
-
-       *value = reg_v;
-       ret = gc0310_read_reg(client, GC0310_8BIT,
-                                       GC0310_AEC_PK_EXPO_H,
-                                       &reg_v);
-       if (ret)
-               goto err;
-
-       *value = *value + (reg_v << 8);
-err:
-       return ret;
-}
-
-static int gc0310_s_ctrl(struct v4l2_ctrl *ctrl)
-{
-       struct gc0310_device *dev =
-           container_of(ctrl->handler, struct gc0310_device, ctrl_handler);
-       struct i2c_client *client = v4l2_get_subdevdata(&dev->sd);
-       int ret = 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_VFLIP:
-               dev_dbg(&client->dev, "%s: CID_VFLIP:%d.\n",
-                       __func__, ctrl->val);
-               ret = gc0310_v_flip(&dev->sd, ctrl->val);
-               break;
-       case V4L2_CID_HFLIP:
-               dev_dbg(&client->dev, "%s: CID_HFLIP:%d.\n",
-                       __func__, ctrl->val);
-               ret = gc0310_h_flip(&dev->sd, ctrl->val);
-               break;
-       default:
-               ret = -EINVAL;
-       }
-       return ret;
-}
-
-static int gc0310_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
-{
-       struct gc0310_device *dev =
-           container_of(ctrl->handler, struct gc0310_device, ctrl_handler);
-       int ret = 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_EXPOSURE_ABSOLUTE:
-               ret = gc0310_q_exposure(&dev->sd, &ctrl->val);
-               break;
-       case V4L2_CID_FOCAL_ABSOLUTE:
-               ret = gc0310_g_focal(&dev->sd, &ctrl->val);
-               break;
-       case V4L2_CID_FNUMBER_ABSOLUTE:
-               ret = gc0310_g_fnumber(&dev->sd, &ctrl->val);
-               break;
-       case V4L2_CID_FNUMBER_RANGE:
-               ret = gc0310_g_fnumber_range(&dev->sd, &ctrl->val);
-               break;
-       case V4L2_CID_BIN_FACTOR_HORZ:
-               ret = gc0310_g_bin_factor_x(&dev->sd, &ctrl->val);
-               break;
-       case V4L2_CID_BIN_FACTOR_VERT:
-               ret = gc0310_g_bin_factor_y(&dev->sd, &ctrl->val);
-               break;
-       default:
-               ret = -EINVAL;
-       }
-
-       return ret;
-}
-
-static const struct v4l2_ctrl_ops ctrl_ops = {
-       .s_ctrl = gc0310_s_ctrl,
-       .g_volatile_ctrl = gc0310_g_volatile_ctrl
-};
-
-struct v4l2_ctrl_config gc0310_controls[] = {
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_EXPOSURE_ABSOLUTE,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .name = "exposure",
-        .min = 0x0,
-        .max = 0xffff,
-        .step = 0x01,
-        .def = 0x00,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_VFLIP,
-        .type = V4L2_CTRL_TYPE_BOOLEAN,
-        .name = "Flip",
-        .min = 0,
-        .max = 1,
-        .step = 1,
-        .def = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_HFLIP,
-        .type = V4L2_CTRL_TYPE_BOOLEAN,
-        .name = "Mirror",
-        .min = 0,
-        .max = 1,
-        .step = 1,
-        .def = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_FOCAL_ABSOLUTE,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .name = "focal length",
-        .min = GC0310_FOCAL_LENGTH_DEFAULT,
-        .max = GC0310_FOCAL_LENGTH_DEFAULT,
-        .step = 0x01,
-        .def = GC0310_FOCAL_LENGTH_DEFAULT,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_FNUMBER_ABSOLUTE,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .name = "f-number",
-        .min = GC0310_F_NUMBER_DEFAULT,
-        .max = GC0310_F_NUMBER_DEFAULT,
-        .step = 0x01,
-        .def = GC0310_F_NUMBER_DEFAULT,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_FNUMBER_RANGE,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .name = "f-number range",
-        .min = GC0310_F_NUMBER_RANGE,
-        .max = GC0310_F_NUMBER_RANGE,
-        .step = 0x01,
-        .def = GC0310_F_NUMBER_RANGE,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_BIN_FACTOR_HORZ,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .name = "horizontal binning factor",
-        .min = 0,
-        .max = GC0310_BIN_FACTOR_MAX,
-        .step = 1,
-        .def = 0,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_BIN_FACTOR_VERT,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .name = "vertical binning factor",
-        .min = 0,
-        .max = GC0310_BIN_FACTOR_MAX,
-        .step = 1,
-        .def = 0,
-        .flags = 0,
-        },
-};
-
-static int gc0310_init(struct v4l2_subdev *sd)
-{
-       int ret;
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct gc0310_device *dev = to_gc0310_sensor(sd);
-
-       pr_info("%s S\n", __func__);
-       mutex_lock(&dev->input_lock);
-
-       /* set inital registers */
-       ret  = gc0310_write_reg_array(client, gc0310_reset_register);
-
-       /* restore settings */
-       gc0310_res = gc0310_res_preview;
-       N_RES = N_RES_PREVIEW;
-
-       mutex_unlock(&dev->input_lock);
-
-       pr_info("%s E\n", __func__);
-       return 0;
-}
-
-static int power_ctrl(struct v4l2_subdev *sd, bool flag)
-{
-       int ret = 0;
-       struct gc0310_device *dev = to_gc0310_sensor(sd);
-       if (!dev || !dev->platform_data)
-               return -ENODEV;
-
-       /* Non-gmin platforms use the legacy callback */
-       if (dev->platform_data->power_ctrl)
-               return dev->platform_data->power_ctrl(sd, flag);
-
-       if (flag) {
-               /* The upstream module driver (written to Crystal
-                * Cove) had this logic to pulse the rails low first.
-                * This appears to break things on the MRD7 with the
-                * X-Powers PMIC...
-                *
-                *     ret = dev->platform_data->v1p8_ctrl(sd, 0);
-                *     ret |= dev->platform_data->v2p8_ctrl(sd, 0);
-                *     mdelay(50);
-                */
-               ret |= dev->platform_data->v1p8_ctrl(sd, 1);
-               ret |= dev->platform_data->v2p8_ctrl(sd, 1);
-               usleep_range(10000, 15000);
-       }
-
-       if (!flag || ret) {
-               ret |= dev->platform_data->v1p8_ctrl(sd, 0);
-               ret |= dev->platform_data->v2p8_ctrl(sd, 0);
-       }
-       return ret;
-}
-
-static int gpio_ctrl(struct v4l2_subdev *sd, bool flag)
-{
-       int ret;
-       struct gc0310_device *dev = to_gc0310_sensor(sd);
-
-       if (!dev || !dev->platform_data)
-               return -ENODEV;
-
-       /* Non-gmin platforms use the legacy callback */
-       if (dev->platform_data->gpio_ctrl)
-               return dev->platform_data->gpio_ctrl(sd, flag);
-
-       /* GPIO0 == "reset" (active low), GPIO1 == "power down" */
-       if (flag) {
-               /* Pulse reset, then release power down */
-               ret = dev->platform_data->gpio0_ctrl(sd, 0);
-               usleep_range(5000, 10000);
-               ret |= dev->platform_data->gpio0_ctrl(sd, 1);
-               usleep_range(10000, 15000);
-               ret |= dev->platform_data->gpio1_ctrl(sd, 0);
-               usleep_range(10000, 15000);
-       } else {
-               ret = dev->platform_data->gpio1_ctrl(sd, 1);
-               ret |= dev->platform_data->gpio0_ctrl(sd, 0);
-       }
-       return ret;
-}
-
-
-static int power_down(struct v4l2_subdev *sd);
-
-static int power_up(struct v4l2_subdev *sd)
-{
-       struct gc0310_device *dev = to_gc0310_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret;
-
-       pr_info("%s S\n", __func__);
-       if (!dev->platform_data) {
-               dev_err(&client->dev,
-                       "no camera_sensor_platform_data");
-               return -ENODEV;
-       }
-
-       /* power control */
-       ret = power_ctrl(sd, 1);
-       if (ret)
-               goto fail_power;
-
-       /* flis clock control */
-       ret = dev->platform_data->flisclk_ctrl(sd, 1);
-       if (ret)
-               goto fail_clk;
-
-       /* gpio ctrl */
-       ret = gpio_ctrl(sd, 1);
-       if (ret) {
-               ret = gpio_ctrl(sd, 1);
-               if (ret)
-                       goto fail_gpio;
-       }
-
-       msleep(100);
-
-       pr_info("%s E\n", __func__);
-       return 0;
-
-fail_gpio:
-       dev->platform_data->flisclk_ctrl(sd, 0);
-fail_clk:
-       power_ctrl(sd, 0);
-fail_power:
-       dev_err(&client->dev, "sensor power-up failed\n");
-
-       return ret;
-}
-
-static int power_down(struct v4l2_subdev *sd)
-{
-       struct gc0310_device *dev = to_gc0310_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret = 0;
-
-       if (!dev->platform_data) {
-               dev_err(&client->dev,
-                       "no camera_sensor_platform_data");
-               return -ENODEV;
-       }
-
-       /* gpio ctrl */
-       ret = gpio_ctrl(sd, 0);
-       if (ret) {
-               ret = gpio_ctrl(sd, 0);
-               if (ret)
-                       dev_err(&client->dev, "gpio failed 2\n");
-       }
-
-       ret = dev->platform_data->flisclk_ctrl(sd, 0);
-       if (ret)
-               dev_err(&client->dev, "flisclk failed\n");
-
-       /* power control */
-       ret = power_ctrl(sd, 0);
-       if (ret)
-               dev_err(&client->dev, "vprog failed.\n");
-
-       return ret;
-}
-
-static int gc0310_s_power(struct v4l2_subdev *sd, int on)
-{
-       int ret;
-       if (on == 0)
-               return power_down(sd);
-       else {
-               ret = power_up(sd);
-               if (!ret)
-                       return gc0310_init(sd);
-       }
-       return ret;
-}
-
-/*
- * distance - calculate the distance
- * @res: resolution
- * @w: width
- * @h: height
- *
- * Get the gap between resolution and w/h.
- * res->width/height smaller than w/h wouldn't be considered.
- * Returns the value of gap or -1 if fail.
- */
-#define LARGEST_ALLOWED_RATIO_MISMATCH 800
-static int distance(struct gc0310_resolution *res, u32 w, u32 h)
-{
-       unsigned int w_ratio = (res->width << 13) / w;
-       unsigned int h_ratio;
-       int match;
-
-       if (h == 0)
-               return -1;
-       h_ratio = (res->height << 13) / h;
-       if (h_ratio == 0)
-               return -1;
-       match   = abs(((w_ratio << 13) / h_ratio) - ((int)8192));
-
-       if ((w_ratio < (int)8192) || (h_ratio < (int)8192)  ||
-               (match > LARGEST_ALLOWED_RATIO_MISMATCH))
-               return -1;
-
-       return w_ratio + h_ratio;
-}
-
-/* Return the nearest higher resolution index */
-static int nearest_resolution_index(int w, int h)
-{
-       int i;
-       int idx = -1;
-       int dist;
-       int min_dist = INT_MAX;
-       struct gc0310_resolution *tmp_res = NULL;
-
-       for (i = 0; i < N_RES; i++) {
-               tmp_res = &gc0310_res[i];
-               dist = distance(tmp_res, w, h);
-               if (dist == -1)
-                       continue;
-               if (dist < min_dist) {
-                       min_dist = dist;
-                       idx = i;
-               }
-       }
-
-       return idx;
-}
-
-static int get_resolution_index(int w, int h)
-{
-       int i;
-
-       for (i = 0; i < N_RES; i++) {
-               if (w != gc0310_res[i].width)
-                       continue;
-               if (h != gc0310_res[i].height)
-                       continue;
-
-               return i;
-       }
-
-       return -1;
-}
-
-
-/* TODO: remove it. */
-static int startup(struct v4l2_subdev *sd)
-{
-       struct gc0310_device *dev = to_gc0310_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret = 0;
-
-       pr_info("%s S\n", __func__);
-
-       ret = gc0310_write_reg_array(client, gc0310_res[dev->fmt_idx].regs);
-       if (ret) {
-               dev_err(&client->dev, "gc0310 write register err.\n");
-               return ret;
-       }
-
-       pr_info("%s E\n", __func__);
-       return ret;
-}
-
-static int gc0310_set_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
-                         struct v4l2_subdev_format *format)
-{
-       struct v4l2_mbus_framefmt *fmt = &format->format;
-       struct gc0310_device *dev = to_gc0310_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct camera_mipi_info *gc0310_info = NULL;
-       int ret = 0;
-       int idx = 0;
-       pr_info("%s S\n", __func__);
-
-       if (format->pad)
-               return -EINVAL;
-
-       if (!fmt)
-               return -EINVAL;
-
-       gc0310_info = v4l2_get_subdev_hostdata(sd);
-       if (!gc0310_info)
-               return -EINVAL;
-
-       mutex_lock(&dev->input_lock);
-
-       idx = nearest_resolution_index(fmt->width, fmt->height);
-       if (idx == -1) {
-               /* return the largest resolution */
-               fmt->width = gc0310_res[N_RES - 1].width;
-               fmt->height = gc0310_res[N_RES - 1].height;
-       } else {
-               fmt->width = gc0310_res[idx].width;
-               fmt->height = gc0310_res[idx].height;
-       }
-       fmt->code = MEDIA_BUS_FMT_SGRBG8_1X8;
-
-       if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
-               cfg->try_fmt = *fmt;
-               mutex_unlock(&dev->input_lock);
-               return 0;
-       }
-
-       dev->fmt_idx = get_resolution_index(fmt->width, fmt->height);
-       if (dev->fmt_idx == -1) {
-               dev_err(&client->dev, "get resolution fail\n");
-               mutex_unlock(&dev->input_lock);
-               return -EINVAL;
-       }
-
-       printk("%s: before gc0310_write_reg_array %s\n", __FUNCTION__,
-              gc0310_res[dev->fmt_idx].desc);
-       ret = startup(sd);
-       if (ret) {
-               dev_err(&client->dev, "gc0310 startup err\n");
-               goto err;
-       }
-
-       ret = gc0310_get_intg_factor(client, gc0310_info,
-                                    &gc0310_res[dev->fmt_idx]);
-       if (ret) {
-               dev_err(&client->dev, "failed to get integration_factor\n");
-               goto err;
-       }
-
-       pr_info("%s E\n", __func__);
-err:
-       mutex_unlock(&dev->input_lock);
-       return ret;
-}
-
-static int gc0310_get_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
-                         struct v4l2_subdev_format *format)
-{
-       struct v4l2_mbus_framefmt *fmt = &format->format;
-       struct gc0310_device *dev = to_gc0310_sensor(sd);
-
-       if (format->pad)
-               return -EINVAL;
-
-       if (!fmt)
-               return -EINVAL;
-
-       fmt->width = gc0310_res[dev->fmt_idx].width;
-       fmt->height = gc0310_res[dev->fmt_idx].height;
-       fmt->code = MEDIA_BUS_FMT_SGRBG8_1X8;
-
-       return 0;
-}
-
-static int gc0310_detect(struct i2c_client *client)
-{
-       struct i2c_adapter *adapter = client->adapter;
-       u8 high, low;
-       int ret;
-       u16 id;
-
-       pr_info("%s S\n", __func__);
-       if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
-               return -ENODEV;
-
-       ret = gc0310_read_reg(client, GC0310_8BIT,
-                                       GC0310_SC_CMMN_CHIP_ID_H, &high);
-       if (ret) {
-               dev_err(&client->dev, "read sensor_id_high failed\n");
-               return -ENODEV;
-       }
-       ret = gc0310_read_reg(client, GC0310_8BIT,
-                                       GC0310_SC_CMMN_CHIP_ID_L, &low);
-       if (ret) {
-               dev_err(&client->dev, "read sensor_id_low failed\n");
-               return -ENODEV;
-       }
-       id = ((((u16) high) << 8) | (u16) low);
-       pr_info("sensor ID = 0x%x\n", id);
-
-       if (id != GC0310_ID) {
-               dev_err(&client->dev, "sensor ID error, read id = 0x%x, target id = 0x%x\n", id, GC0310_ID);
-               return -ENODEV;
-       }
-
-       dev_dbg(&client->dev, "detect gc0310 success\n");
-
-       pr_info("%s E\n", __func__);
-
-       return 0;
-}
-
-static int gc0310_s_stream(struct v4l2_subdev *sd, int enable)
-{
-       struct gc0310_device *dev = to_gc0310_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret;
-
-       pr_info("%s S enable=%d\n", __func__, enable);
-       mutex_lock(&dev->input_lock);
-
-       if (enable) {
-               /* enable per frame MIPI and sensor ctrl reset  */
-               ret = gc0310_write_reg(client, GC0310_8BIT,
-                                               0xFE, 0x30);
-               if (ret) {
-                       mutex_unlock(&dev->input_lock);
-                       return ret;
-               }
-       }
-
-       ret = gc0310_write_reg(client, GC0310_8BIT,
-                               GC0310_RESET_RELATED, GC0310_REGISTER_PAGE_3);
-       if (ret) {
-               mutex_unlock(&dev->input_lock);
-               return ret;
-       }
-
-       ret = gc0310_write_reg(client, GC0310_8BIT, GC0310_SW_STREAM,
-                               enable ? GC0310_START_STREAMING :
-                               GC0310_STOP_STREAMING);
-       if (ret) {
-               mutex_unlock(&dev->input_lock);
-               return ret;
-       }
-
-       ret = gc0310_write_reg(client, GC0310_8BIT,
-                               GC0310_RESET_RELATED, GC0310_REGISTER_PAGE_0);
-       if (ret) {
-               mutex_unlock(&dev->input_lock);
-               return ret;
-       }
-
-       mutex_unlock(&dev->input_lock);
-       pr_info("%s E\n", __func__);
-       return ret;
-}
-
-
-static int gc0310_s_config(struct v4l2_subdev *sd,
-                          int irq, void *platform_data)
-{
-       struct gc0310_device *dev = to_gc0310_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret = 0;
-
-       pr_info("%s S\n", __func__);
-       if (!platform_data)
-               return -ENODEV;
-
-       dev->platform_data =
-               (struct camera_sensor_platform_data *)platform_data;
-
-       mutex_lock(&dev->input_lock);
-       if (dev->platform_data->platform_init) {
-               ret = dev->platform_data->platform_init(client);
-               if (ret) {
-                       dev_err(&client->dev, "platform init err\n");
-                       goto platform_init_failed;
-               }
-       }
-       /* power off the module, then power on it in future
-        * as first power on by board may not fulfill the
-        * power on sequqence needed by the module
-        */
-       ret = power_down(sd);
-       if (ret) {
-               dev_err(&client->dev, "gc0310 power-off err.\n");
-               goto fail_power_off;
-       }
-
-       ret = power_up(sd);
-       if (ret) {
-               dev_err(&client->dev, "gc0310 power-up err.\n");
-               goto fail_power_on;
-       }
-
-       ret = dev->platform_data->csi_cfg(sd, 1);
-       if (ret)
-               goto fail_csi_cfg;
-
-       /* config & detect sensor */
-       ret = gc0310_detect(client);
-       if (ret) {
-               dev_err(&client->dev, "gc0310_detect err s_config.\n");
-               goto fail_csi_cfg;
-       }
-
-       /* turn off sensor, after probed */
-       ret = power_down(sd);
-       if (ret) {
-               dev_err(&client->dev, "gc0310 power-off err.\n");
-               goto fail_csi_cfg;
-       }
-       mutex_unlock(&dev->input_lock);
-
-       pr_info("%s E\n", __func__);
-       return 0;
-
-fail_csi_cfg:
-       dev->platform_data->csi_cfg(sd, 0);
-fail_power_on:
-       power_down(sd);
-       dev_err(&client->dev, "sensor power-gating failed\n");
-fail_power_off:
-       if (dev->platform_data->platform_deinit)
-               dev->platform_data->platform_deinit();
-platform_init_failed:
-       mutex_unlock(&dev->input_lock);
-       return ret;
-}
-
-static int gc0310_g_parm(struct v4l2_subdev *sd,
-                       struct v4l2_streamparm *param)
-{
-       struct gc0310_device *dev = to_gc0310_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (!param)
-               return -EINVAL;
-
-       if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-               dev_err(&client->dev,  "unsupported buffer type.\n");
-               return -EINVAL;
-       }
-
-       memset(param, 0, sizeof(*param));
-       param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-       if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) {
-               param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
-               param->parm.capture.timeperframe.numerator = 1;
-               param->parm.capture.capturemode = dev->run_mode;
-               param->parm.capture.timeperframe.denominator =
-                       gc0310_res[dev->fmt_idx].fps;
-       }
-       return 0;
-}
-
-static int gc0310_s_parm(struct v4l2_subdev *sd,
-                       struct v4l2_streamparm *param)
-{
-       struct gc0310_device *dev = to_gc0310_sensor(sd);
-       dev->run_mode = param->parm.capture.capturemode;
-
-       mutex_lock(&dev->input_lock);
-       switch (dev->run_mode) {
-       case CI_MODE_VIDEO:
-               gc0310_res = gc0310_res_video;
-               N_RES = N_RES_VIDEO;
-               break;
-       case CI_MODE_STILL_CAPTURE:
-               gc0310_res = gc0310_res_still;
-               N_RES = N_RES_STILL;
-               break;
-       default:
-               gc0310_res = gc0310_res_preview;
-               N_RES = N_RES_PREVIEW;
-       }
-       mutex_unlock(&dev->input_lock);
-       return 0;
-}
-
-static int gc0310_g_frame_interval(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_frame_interval *interval)
-{
-       struct gc0310_device *dev = to_gc0310_sensor(sd);
-
-       interval->interval.numerator = 1;
-       interval->interval.denominator = gc0310_res[dev->fmt_idx].fps;
-
-       return 0;
-}
-
-static int gc0310_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
-                                struct v4l2_subdev_mbus_code_enum *code)
-{
-       if (code->index >= MAX_FMTS)
-               return -EINVAL;
-
-       code->code = MEDIA_BUS_FMT_SGRBG8_1X8;
-       return 0;
-}
-
-static int gc0310_enum_frame_size(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
-                                 struct v4l2_subdev_frame_size_enum *fse)
-{
-       int index = fse->index;
-
-       if (index >= N_RES)
-               return -EINVAL;
-
-       fse->min_width = gc0310_res[index].width;
-       fse->min_height = gc0310_res[index].height;
-       fse->max_width = gc0310_res[index].width;
-       fse->max_height = gc0310_res[index].height;
-
-       return 0;
-
-}
-
-
-static int gc0310_g_skip_frames(struct v4l2_subdev *sd, u32 *frames)
-{
-       struct gc0310_device *dev = to_gc0310_sensor(sd);
-
-       mutex_lock(&dev->input_lock);
-       *frames = gc0310_res[dev->fmt_idx].skip_frames;
-       mutex_unlock(&dev->input_lock);
-
-       return 0;
-}
-
-static const struct v4l2_subdev_sensor_ops gc0310_sensor_ops = {
-       .g_skip_frames  = gc0310_g_skip_frames,
-};
-
-static const struct v4l2_subdev_video_ops gc0310_video_ops = {
-       .s_stream = gc0310_s_stream,
-       .g_parm = gc0310_g_parm,
-       .s_parm = gc0310_s_parm,
-       .g_frame_interval = gc0310_g_frame_interval,
-};
-
-static const struct v4l2_subdev_core_ops gc0310_core_ops = {
-       .s_power = gc0310_s_power,
-       .ioctl = gc0310_ioctl,
-};
-
-static const struct v4l2_subdev_pad_ops gc0310_pad_ops = {
-       .enum_mbus_code = gc0310_enum_mbus_code,
-       .enum_frame_size = gc0310_enum_frame_size,
-       .get_fmt = gc0310_get_fmt,
-       .set_fmt = gc0310_set_fmt,
-};
-
-static const struct v4l2_subdev_ops gc0310_ops = {
-       .core = &gc0310_core_ops,
-       .video = &gc0310_video_ops,
-       .pad = &gc0310_pad_ops,
-       .sensor = &gc0310_sensor_ops,
-};
-
-static int gc0310_remove(struct i2c_client *client)
-{
-       struct v4l2_subdev *sd = i2c_get_clientdata(client);
-       struct gc0310_device *dev = to_gc0310_sensor(sd);
-       dev_dbg(&client->dev, "gc0310_remove...\n");
-
-       if (dev->platform_data->platform_deinit)
-               dev->platform_data->platform_deinit();
-
-       dev->platform_data->csi_cfg(sd, 0);
-
-       v4l2_device_unregister_subdev(sd);
-       media_entity_cleanup(&dev->sd.entity);
-       v4l2_ctrl_handler_free(&dev->ctrl_handler);
-       kfree(dev);
-
-       return 0;
-}
-
-static int gc0310_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
-{
-       struct gc0310_device *dev;
-       int ret;
-       void *pdata;
-       unsigned int i;
-
-       pr_info("%s S\n", __func__);
-       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-       if (!dev) {
-               dev_err(&client->dev, "out of memory\n");
-               return -ENOMEM;
-       }
-
-       mutex_init(&dev->input_lock);
-
-       dev->fmt_idx = 0;
-       v4l2_i2c_subdev_init(&(dev->sd), client, &gc0310_ops);
-
-       if (ACPI_COMPANION(&client->dev))
-               pdata = gmin_camera_platform_data(&dev->sd,
-                                                 ATOMISP_INPUT_FORMAT_RAW_8,
-                                                 atomisp_bayer_order_grbg);
-       else
-               pdata = client->dev.platform_data;
-
-       if (!pdata) {
-               ret = -EINVAL;
-               goto out_free;
-       }
-
-       ret = gc0310_s_config(&dev->sd, client->irq, pdata);
-       if (ret)
-               goto out_free;
-
-       ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA);
-       if (ret)
-               goto out_free;
-
-       dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-       dev->pad.flags = MEDIA_PAD_FL_SOURCE;
-       dev->format.code = MEDIA_BUS_FMT_SGRBG8_1X8;
-       dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
-       ret =
-           v4l2_ctrl_handler_init(&dev->ctrl_handler,
-                                  ARRAY_SIZE(gc0310_controls));
-       if (ret) {
-               gc0310_remove(client);
-               return ret;
-       }
-
-       for (i = 0; i < ARRAY_SIZE(gc0310_controls); i++)
-               v4l2_ctrl_new_custom(&dev->ctrl_handler, &gc0310_controls[i],
-                                    NULL);
-
-       if (dev->ctrl_handler.error) {
-               gc0310_remove(client);
-               return dev->ctrl_handler.error;
-       }
-
-       /* Use same lock for controls as for everything else. */
-       dev->ctrl_handler.lock = &dev->input_lock;
-       dev->sd.ctrl_handler = &dev->ctrl_handler;
-
-       ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad);
-       if (ret)
-               gc0310_remove(client);
-
-       pr_info("%s E\n", __func__);
-       return ret;
-out_free:
-       v4l2_device_unregister_subdev(&dev->sd);
-       kfree(dev);
-       return ret;
-}
-
-static const struct acpi_device_id gc0310_acpi_match[] = {
-       {"XXGC0310"},
-       {"INT0310"},
-       {},
-};
-
-MODULE_DEVICE_TABLE(acpi, gc0310_acpi_match);
-
-MODULE_DEVICE_TABLE(i2c, gc0310_id);
-static struct i2c_driver gc0310_driver = {
-       .driver = {
-               .name = GC0310_NAME,
-               .acpi_match_table = ACPI_PTR(gc0310_acpi_match),
-       },
-       .probe = gc0310_probe,
-       .remove = gc0310_remove,
-       .id_table = gc0310_id,
-};
-
-static int init_gc0310(void)
-{
-       return i2c_add_driver(&gc0310_driver);
-}
-
-static void exit_gc0310(void)
-{
-
-       i2c_del_driver(&gc0310_driver);
-}
-
-module_init(init_gc0310);
-module_exit(exit_gc0310);
-
-MODULE_AUTHOR("Lai, Angie <angie.lai@intel.com>");
-MODULE_DESCRIPTION("A low-level driver for GalaxyCore GC0310 sensors");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/media/atomisp/i2c/gc2235.c b/drivers/staging/media/atomisp/i2c/gc2235.c
deleted file mode 100644 (file)
index e43d31e..0000000
+++ /dev/null
@@ -1,1219 +0,0 @@
-/*
- * Support for GalaxyCore GC2235 2M camera sensor.
- *
- * Copyright (c) 2014 Intel Corporation. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/kmod.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/gpio.h>
-#include <linux/moduleparam.h>
-#include <media/v4l2-device.h>
-#include "../include/linux/atomisp_gmin_platform.h"
-#include <linux/acpi.h>
-#include <linux/io.h>
-
-#include "gc2235.h"
-
-/* i2c read/write stuff */
-static int gc2235_read_reg(struct i2c_client *client,
-                          u16 data_length, u16 reg, u16 *val)
-{
-       int err;
-       struct i2c_msg msg[2];
-       unsigned char data[6];
-
-       if (!client->adapter) {
-               dev_err(&client->dev, "%s error, no client->adapter\n",
-                       __func__);
-               return -ENODEV;
-       }
-
-       if (data_length != GC2235_8BIT) {
-               dev_err(&client->dev, "%s error, invalid data length\n",
-                       __func__);
-               return -EINVAL;
-       }
-
-       memset(msg, 0, sizeof(msg));
-
-       msg[0].addr = client->addr;
-       msg[0].flags = 0;
-       msg[0].len = 1;
-       msg[0].buf = data;
-
-       /* high byte goes out first */
-       data[0] = (u8)(reg & 0xff);
-
-       msg[1].addr = client->addr;
-       msg[1].len = data_length;
-       msg[1].flags = I2C_M_RD;
-       msg[1].buf = data;
-
-       err = i2c_transfer(client->adapter, msg, 2);
-       if (err != 2) {
-               if (err >= 0)
-                       err = -EIO;
-               dev_err(&client->dev,
-                       "read from offset 0x%x error %d", reg, err);
-               return err;
-       }
-
-       *val = 0;
-       /* high byte comes first */
-       if (data_length == GC2235_8BIT)
-               *val = (u8)data[0];
-
-       return 0;
-}
-
-static int gc2235_i2c_write(struct i2c_client *client, u16 len, u8 *data)
-{
-       struct i2c_msg msg;
-       const int num_msg = 1;
-       int ret;
-
-       msg.addr = client->addr;
-       msg.flags = 0;
-       msg.len = len;
-       msg.buf = data;
-       ret = i2c_transfer(client->adapter, &msg, 1);
-
-       return ret == num_msg ? 0 : -EIO;
-}
-
-static int gc2235_write_reg(struct i2c_client *client, u16 data_length,
-                                                       u8 reg, u8 val)
-{
-       int ret;
-       unsigned char data[4] = {0};
-       const u16 len = data_length + sizeof(u8); /* 16-bit address + data */
-
-       if (data_length != GC2235_8BIT) {
-               dev_err(&client->dev,
-                       "%s error, invalid data_length\n", __func__);
-               return -EINVAL;
-       }
-
-       /* high byte goes out first */
-       data[0] = reg;
-       data[1] = val;
-
-       ret = gc2235_i2c_write(client, len, data);
-       if (ret)
-               dev_err(&client->dev,
-                       "write error: wrote 0x%x to offset 0x%x error %d",
-                       val, reg, ret);
-
-       return ret;
-}
-
-static int __gc2235_flush_reg_array(struct i2c_client *client,
-                                   struct gc2235_write_ctrl *ctrl)
-{
-       u16 size;
-
-       if (ctrl->index == 0)
-               return 0;
-
-       size = sizeof(u8) + ctrl->index; /* 8-bit address + data */
-       ctrl->index = 0;
-
-       return gc2235_i2c_write(client, size, (u8 *)&ctrl->buffer);
-}
-
-static int __gc2235_buf_reg_array(struct i2c_client *client,
-                                 struct gc2235_write_ctrl *ctrl,
-                                 const struct gc2235_reg *next)
-{
-       int size;
-
-       if (next->type != GC2235_8BIT)
-               return -EINVAL;
-
-       size = 1;
-       ctrl->buffer.data[ctrl->index] = (u8)next->val;
-
-       /* When first item is added, we need to store its starting address */
-       if (ctrl->index == 0)
-               ctrl->buffer.addr = next->reg;
-
-       ctrl->index += size;
-
-       /*
-        * Buffer cannot guarantee free space for u32? Better flush it to avoid
-        * possible lack of memory for next item.
-        */
-       if (ctrl->index + sizeof(u8) >= GC2235_MAX_WRITE_BUF_SIZE)
-               return __gc2235_flush_reg_array(client, ctrl);
-
-       return 0;
-}
-static int __gc2235_write_reg_is_consecutive(struct i2c_client *client,
-                                            struct gc2235_write_ctrl *ctrl,
-                                            const struct gc2235_reg *next)
-{
-       if (ctrl->index == 0)
-               return 1;
-
-       return ctrl->buffer.addr + ctrl->index == next->reg;
-}
-static int gc2235_write_reg_array(struct i2c_client *client,
-                                 const struct gc2235_reg *reglist)
-{
-       const struct gc2235_reg *next = reglist;
-       struct gc2235_write_ctrl ctrl;
-       int err;
-
-       ctrl.index = 0;
-       for (; next->type != GC2235_TOK_TERM; next++) {
-               switch (next->type & GC2235_TOK_MASK) {
-               case GC2235_TOK_DELAY:
-                       err = __gc2235_flush_reg_array(client, &ctrl);
-                       if (err)
-                               return err;
-                       msleep(next->val);
-                       break;
-               default:
-                       /*
-                        * If next address is not consecutive, data needs to be
-                        * flushed before proceed.
-                        */
-                       if (!__gc2235_write_reg_is_consecutive(client, &ctrl,
-                                                               next)) {
-                               err = __gc2235_flush_reg_array(client, &ctrl);
-                               if (err)
-                                       return err;
-                       }
-                       err = __gc2235_buf_reg_array(client, &ctrl, next);
-                       if (err) {
-                               dev_err(&client->dev, "%s: write error, aborted\n",
-                                        __func__);
-                               return err;
-                       }
-                       break;
-               }
-       }
-
-       return __gc2235_flush_reg_array(client, &ctrl);
-}
-
-static int gc2235_g_focal(struct v4l2_subdev *sd, s32 *val)
-{
-       *val = (GC2235_FOCAL_LENGTH_NUM << 16) | GC2235_FOCAL_LENGTH_DEM;
-       return 0;
-}
-
-static int gc2235_g_fnumber(struct v4l2_subdev *sd, s32 *val)
-{
-       /*const f number for imx*/
-       *val = (GC2235_F_NUMBER_DEFAULT_NUM << 16) | GC2235_F_NUMBER_DEM;
-       return 0;
-}
-
-static int gc2235_g_fnumber_range(struct v4l2_subdev *sd, s32 *val)
-{
-       *val = (GC2235_F_NUMBER_DEFAULT_NUM << 24) |
-               (GC2235_F_NUMBER_DEM << 16) |
-               (GC2235_F_NUMBER_DEFAULT_NUM << 8) | GC2235_F_NUMBER_DEM;
-       return 0;
-}
-
-
-static int gc2235_get_intg_factor(struct i2c_client *client,
-                               struct camera_mipi_info *info,
-                               const struct gc2235_resolution *res)
-{
-       struct v4l2_subdev *sd = i2c_get_clientdata(client);
-       struct gc2235_device *dev = to_gc2235_sensor(sd);
-       struct atomisp_sensor_mode_data *buf = &info->data;
-       u16 reg_val, reg_val_h, dummy;
-       int ret;
-
-       if (!info)
-               return -EINVAL;
-
-       /* pixel clock calculattion */
-       buf->vt_pix_clk_freq_mhz = dev->vt_pix_clk_freq_mhz = 30000000;
-
-       /* get integration time */
-       buf->coarse_integration_time_min = GC2235_COARSE_INTG_TIME_MIN;
-       buf->coarse_integration_time_max_margin =
-                                       GC2235_COARSE_INTG_TIME_MAX_MARGIN;
-
-       buf->fine_integration_time_min = GC2235_FINE_INTG_TIME_MIN;
-       buf->fine_integration_time_max_margin =
-                                       GC2235_FINE_INTG_TIME_MAX_MARGIN;
-
-       buf->fine_integration_time_def = GC2235_FINE_INTG_TIME_MIN;
-       buf->frame_length_lines = res->lines_per_frame;
-       buf->line_length_pck = res->pixels_per_line;
-       buf->read_mode = res->bin_mode;
-
-       /* get the cropping and output resolution to ISP for this mode. */
-       ret =  gc2235_read_reg(client, GC2235_8BIT,
-                                       GC2235_H_CROP_START_H, &reg_val_h);
-       ret =  gc2235_read_reg(client, GC2235_8BIT,
-                                       GC2235_H_CROP_START_L, &reg_val);
-       if (ret)
-               return ret;
-
-       buf->crop_horizontal_start = (reg_val_h << 8) | reg_val;
-
-       ret =  gc2235_read_reg(client, GC2235_8BIT,
-                                       GC2235_V_CROP_START_H, &reg_val_h);
-       ret =  gc2235_read_reg(client, GC2235_8BIT,
-                                       GC2235_V_CROP_START_L, &reg_val);
-       if (ret)
-               return ret;
-
-       buf->crop_vertical_start = (reg_val_h << 8) | reg_val;
-
-       ret = gc2235_read_reg(client, GC2235_8BIT,
-                                       GC2235_H_OUTSIZE_H, &reg_val_h);
-       ret = gc2235_read_reg(client, GC2235_8BIT,
-                                       GC2235_H_OUTSIZE_L, &reg_val);
-       if (ret)
-               return ret;
-       buf->output_width = (reg_val_h << 8) | reg_val;
-
-       ret = gc2235_read_reg(client, GC2235_8BIT,
-                                       GC2235_V_OUTSIZE_H, &reg_val_h);
-       ret = gc2235_read_reg(client, GC2235_8BIT,
-                                       GC2235_V_OUTSIZE_L, &reg_val);
-       if (ret)
-               return ret;
-       buf->output_height = (reg_val_h << 8) | reg_val;
-
-       buf->crop_horizontal_end = buf->crop_horizontal_start +
-                                               buf->output_width - 1;
-       buf->crop_vertical_end = buf->crop_vertical_start +
-                                               buf->output_height - 1;
-
-       ret = gc2235_read_reg(client, GC2235_8BIT,
-                                       GC2235_HB_H, &reg_val_h);
-       ret = gc2235_read_reg(client, GC2235_8BIT,
-                                       GC2235_HB_L, &reg_val);
-       if (ret)
-               return ret;
-
-       dummy = (reg_val_h << 8) | reg_val;
-
-       ret = gc2235_read_reg(client, GC2235_8BIT,
-                                       GC2235_SH_DELAY_H, &reg_val_h);
-       ret = gc2235_read_reg(client, GC2235_8BIT,
-                                       GC2235_SH_DELAY_L, &reg_val);
-
-#if 0
-       buf->line_length_pck = buf->output_width + 16 + dummy +
-                               (((u16)reg_val_h << 8) | (u16)reg_val) + 4;
-#endif
-       ret = gc2235_read_reg(client, GC2235_8BIT,
-                                       GC2235_VB_H, &reg_val_h);
-       ret = gc2235_read_reg(client, GC2235_8BIT,
-                                       GC2235_VB_L, &reg_val);
-       if (ret)
-               return ret;
-
-#if 0
-       buf->frame_length_lines = buf->output_height + 32 +
-                               (((u16)reg_val_h << 8) | (u16)reg_val);
-#endif
-       buf->binning_factor_x = res->bin_factor_x ?
-                                       res->bin_factor_x : 1;
-       buf->binning_factor_y = res->bin_factor_y ?
-                                       res->bin_factor_y : 1;
-       return 0;
-}
-
-static long __gc2235_set_exposure(struct v4l2_subdev *sd, int coarse_itg,
-                                int gain, int digitgain)
-
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       u16 coarse_integration = (u16)coarse_itg;
-       int ret = 0;
-       u16 expo_coarse_h, expo_coarse_l, gain_val = 0xF0, gain_val2 = 0xF0;
-       expo_coarse_h = coarse_integration >> 8;
-       expo_coarse_l = coarse_integration & 0xff;
-
-       ret = gc2235_write_reg(client, GC2235_8BIT,
-                                       GC2235_EXPOSURE_H, expo_coarse_h);
-       ret = gc2235_write_reg(client, GC2235_8BIT,
-                                       GC2235_EXPOSURE_L, expo_coarse_l);
-
-       if (gain <= 0x58) {
-               gain_val = 0x40;
-               gain_val2 = 0x58;
-       } else if (gain < 256) {
-               gain_val = 0x40;
-               gain_val2 = gain;
-       } else {
-               gain_val2 = 64 * gain / 256;
-               gain_val = 0xff;
-       }
-
-       ret = gc2235_write_reg(client, GC2235_8BIT,
-                                       GC2235_GLOBAL_GAIN, (u8)gain_val);
-       ret = gc2235_write_reg(client, GC2235_8BIT,
-                                       GC2235_PRE_GAIN, (u8)gain_val2);
-
-       return ret;
-}
-
-
-static int gc2235_set_exposure(struct v4l2_subdev *sd, int exposure,
-       int gain, int digitgain)
-{
-       struct gc2235_device *dev = to_gc2235_sensor(sd);
-       int ret;
-
-       mutex_lock(&dev->input_lock);
-       ret = __gc2235_set_exposure(sd, exposure, gain, digitgain);
-       mutex_unlock(&dev->input_lock);
-
-       return ret;
-}
-
-static long gc2235_s_exposure(struct v4l2_subdev *sd,
-                              struct atomisp_exposure *exposure)
-{
-       int exp = exposure->integration_time[0];
-       int gain = exposure->gain[0];
-       int digitgain = exposure->gain[1];
-
-       /* we should not accept the invalid value below. */
-       if (gain == 0) {
-               struct i2c_client *client = v4l2_get_subdevdata(sd);
-               v4l2_err(client, "%s: invalid value\n", __func__);
-               return -EINVAL;
-       }
-
-       return gc2235_set_exposure(sd, exp, gain, digitgain);
-}
-static long gc2235_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
-{
-       switch (cmd) {
-       case ATOMISP_IOC_S_EXPOSURE:
-               return gc2235_s_exposure(sd, arg);
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-/* This returns the exposure time being used. This should only be used
- * for filling in EXIF data, not for actual image processing.
- */
-static int gc2235_q_exposure(struct v4l2_subdev *sd, s32 *value)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       u16 reg_v, reg_v2;
-       int ret;
-
-       /* get exposure */
-       ret = gc2235_read_reg(client, GC2235_8BIT,
-                                       GC2235_EXPOSURE_L,
-                                       &reg_v);
-       if (ret)
-               goto err;
-
-       ret = gc2235_read_reg(client, GC2235_8BIT,
-                                       GC2235_EXPOSURE_H,
-                                       &reg_v2);
-       if (ret)
-               goto err;
-
-       reg_v += reg_v2 << 8;
-
-       *value = reg_v;
-err:
-       return ret;
-}
-
-static int gc2235_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
-{
-       struct gc2235_device *dev =
-           container_of(ctrl->handler, struct gc2235_device, ctrl_handler);
-       int ret = 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_EXPOSURE_ABSOLUTE:
-               ret = gc2235_q_exposure(&dev->sd, &ctrl->val);
-               break;
-       case V4L2_CID_FOCAL_ABSOLUTE:
-               ret = gc2235_g_focal(&dev->sd, &ctrl->val);
-               break;
-       case V4L2_CID_FNUMBER_ABSOLUTE:
-               ret = gc2235_g_fnumber(&dev->sd, &ctrl->val);
-               break;
-       case V4L2_CID_FNUMBER_RANGE:
-               ret = gc2235_g_fnumber_range(&dev->sd, &ctrl->val);
-               break;
-       default:
-               ret = -EINVAL;
-       }
-
-       return ret;
-}
-
-static const struct v4l2_ctrl_ops ctrl_ops = {
-       .g_volatile_ctrl = gc2235_g_volatile_ctrl
-};
-
-static struct v4l2_ctrl_config gc2235_controls[] = {
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_EXPOSURE_ABSOLUTE,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .name = "exposure",
-        .min = 0x0,
-        .max = 0xffff,
-        .step = 0x01,
-        .def = 0x00,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_FOCAL_ABSOLUTE,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .name = "focal length",
-        .min = GC2235_FOCAL_LENGTH_DEFAULT,
-        .max = GC2235_FOCAL_LENGTH_DEFAULT,
-        .step = 0x01,
-        .def = GC2235_FOCAL_LENGTH_DEFAULT,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_FNUMBER_ABSOLUTE,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .name = "f-number",
-        .min = GC2235_F_NUMBER_DEFAULT,
-        .max = GC2235_F_NUMBER_DEFAULT,
-        .step = 0x01,
-        .def = GC2235_F_NUMBER_DEFAULT,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_FNUMBER_RANGE,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .name = "f-number range",
-        .min = GC2235_F_NUMBER_RANGE,
-        .max = GC2235_F_NUMBER_RANGE,
-        .step = 0x01,
-        .def = GC2235_F_NUMBER_RANGE,
-        .flags = 0,
-        },
-};
-
-static int __gc2235_init(struct v4l2_subdev *sd)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       /* restore settings */
-       gc2235_res = gc2235_res_preview;
-       N_RES = N_RES_PREVIEW;
-
-       return gc2235_write_reg_array(client, gc2235_init_settings);
-}
-
-static int is_init;
-
-static int power_ctrl(struct v4l2_subdev *sd, bool flag)
-{
-       int ret = -1;
-       struct gc2235_device *dev = to_gc2235_sensor(sd);
-
-       if (!dev || !dev->platform_data)
-               return -ENODEV;
-
-       /* Non-gmin platforms use the legacy callback */
-       if (dev->platform_data->power_ctrl)
-               return dev->platform_data->power_ctrl(sd, flag);
-
-       if (flag) {
-               ret = dev->platform_data->v1p8_ctrl(sd, 1);
-               usleep_range(60, 90);
-               if (ret == 0)
-                       ret |= dev->platform_data->v2p8_ctrl(sd, 1);
-       } else {
-               ret = dev->platform_data->v1p8_ctrl(sd, 0);
-               ret |= dev->platform_data->v2p8_ctrl(sd, 0);
-       }
-       return ret;
-}
-
-static int gpio_ctrl(struct v4l2_subdev *sd, bool flag)
-{
-       struct gc2235_device *dev = to_gc2235_sensor(sd);
-       int ret = -1;
-
-       if (!dev || !dev->platform_data)
-               return -ENODEV;
-
-       /* Non-gmin platforms use the legacy callback */
-       if (dev->platform_data->gpio_ctrl)
-               return dev->platform_data->gpio_ctrl(sd, flag);
-
-       ret |= dev->platform_data->gpio1_ctrl(sd, !flag);
-       usleep_range(60, 90);
-       return dev->platform_data->gpio0_ctrl(sd, flag);
-}
-
-static int power_up(struct v4l2_subdev *sd)
-{
-       struct gc2235_device *dev = to_gc2235_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret;
-
-       if (!dev->platform_data) {
-               dev_err(&client->dev,
-                       "no camera_sensor_platform_data");
-               return -ENODEV;
-       }
-       /* power control */
-       ret = power_ctrl(sd, 1);
-       if (ret)
-               goto fail_power;
-
-       /* according to DS, at least 5ms is needed between DOVDD and PWDN */
-       usleep_range(5000, 6000);
-
-       ret = dev->platform_data->flisclk_ctrl(sd, 1);
-       if (ret)
-               goto fail_clk;
-       usleep_range(5000, 6000);
-
-       /* gpio ctrl */
-       ret = gpio_ctrl(sd, 1);
-       if (ret) {
-               ret = gpio_ctrl(sd, 1);
-               if (ret)
-                       goto fail_power;
-       }
-
-       msleep(5);
-       return 0;
-
-fail_clk:
-       gpio_ctrl(sd, 0);
-fail_power:
-       power_ctrl(sd, 0);
-       dev_err(&client->dev, "sensor power-up failed\n");
-
-       return ret;
-}
-
-static int power_down(struct v4l2_subdev *sd)
-{
-       struct gc2235_device *dev = to_gc2235_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret = 0;
-
-       if (!dev->platform_data) {
-               dev_err(&client->dev,
-                       "no camera_sensor_platform_data");
-               return -ENODEV;
-       }
-       /* gpio ctrl */
-       ret = gpio_ctrl(sd, 0);
-       if (ret) {
-               ret = gpio_ctrl(sd, 0);
-               if (ret)
-                       dev_err(&client->dev, "gpio failed 2\n");
-       }
-
-       ret = dev->platform_data->flisclk_ctrl(sd, 0);
-       if (ret)
-               dev_err(&client->dev, "flisclk failed\n");
-
-       /* power control */
-       ret = power_ctrl(sd, 0);
-       if (ret)
-               dev_err(&client->dev, "vprog failed.\n");
-
-       return ret;
-}
-
-static int gc2235_s_power(struct v4l2_subdev *sd, int on)
-{
-       int ret;
-
-       if (on == 0)
-               ret = power_down(sd);
-       else {
-               ret = power_up(sd);
-               if (!ret)
-                       ret = __gc2235_init(sd);
-               is_init = 1;
-       }
-       return ret;
-}
-
-/*
- * distance - calculate the distance
- * @res: resolution
- * @w: width
- * @h: height
- *
- * Get the gap between resolution and w/h.
- * res->width/height smaller than w/h wouldn't be considered.
- * Returns the value of gap or -1 if fail.
- */
-#define LARGEST_ALLOWED_RATIO_MISMATCH 800
-static int distance(struct gc2235_resolution *res, u32 w, u32 h)
-{
-       unsigned int w_ratio = (res->width << 13) / w;
-       unsigned int h_ratio;
-       int match;
-
-       if (h == 0)
-               return -1;
-       h_ratio = (res->height << 13) / h;
-       if (h_ratio == 0)
-               return -1;
-       match   = abs(((w_ratio << 13) / h_ratio) - 8192);
-
-       if ((w_ratio < 8192) || (h_ratio < 8192) ||
-           (match > LARGEST_ALLOWED_RATIO_MISMATCH))
-               return -1;
-
-       return w_ratio + h_ratio;
-}
-
-/* Return the nearest higher resolution index */
-static int nearest_resolution_index(int w, int h)
-{
-       int i;
-       int idx = -1;
-       int dist;
-       int min_dist = INT_MAX;
-       struct gc2235_resolution *tmp_res = NULL;
-
-       for (i = 0; i < N_RES; i++) {
-               tmp_res = &gc2235_res[i];
-               dist = distance(tmp_res, w, h);
-               if (dist == -1)
-                       continue;
-               if (dist < min_dist) {
-                       min_dist = dist;
-                       idx = i;
-               }
-       }
-
-       return idx;
-}
-
-static int get_resolution_index(int w, int h)
-{
-       int i;
-
-       for (i = 0; i < N_RES; i++) {
-               if (w != gc2235_res[i].width)
-                       continue;
-               if (h != gc2235_res[i].height)
-                       continue;
-
-               return i;
-       }
-
-       return -1;
-}
-
-static int startup(struct v4l2_subdev *sd)
-{
-       struct gc2235_device *dev = to_gc2235_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret = 0;
-       if (is_init == 0) {
-               /* force gc2235 to do a reset in res change, otherwise it
-               * can not output normal after switching res. and it is not
-               * necessary for first time run up after power on, for the sack
-               * of performance
-               */
-               power_down(sd);
-               power_up(sd);
-               gc2235_write_reg_array(client, gc2235_init_settings);
-       }
-
-       ret = gc2235_write_reg_array(client, gc2235_res[dev->fmt_idx].regs);
-       if (ret) {
-               dev_err(&client->dev, "gc2235 write register err.\n");
-               return ret;
-       }
-       is_init = 0;
-
-       return ret;
-}
-
-static int gc2235_set_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
-                         struct v4l2_subdev_format *format)
-{
-
-       struct v4l2_mbus_framefmt *fmt = &format->format;
-       struct gc2235_device *dev = to_gc2235_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct camera_mipi_info *gc2235_info = NULL;
-       int ret = 0;
-       int idx;
-
-       gc2235_info = v4l2_get_subdev_hostdata(sd);
-       if (!gc2235_info)
-               return -EINVAL;
-       if (format->pad)
-               return -EINVAL;
-       if (!fmt)
-               return -EINVAL;
-       mutex_lock(&dev->input_lock);
-       idx = nearest_resolution_index(fmt->width, fmt->height);
-       if (idx == -1) {
-               /* return the largest resolution */
-               fmt->width = gc2235_res[N_RES - 1].width;
-               fmt->height = gc2235_res[N_RES - 1].height;
-       } else {
-               fmt->width = gc2235_res[idx].width;
-               fmt->height = gc2235_res[idx].height;
-       }
-       fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
-       if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
-               cfg->try_fmt = *fmt;
-               mutex_unlock(&dev->input_lock);
-               return 0;
-       }
-
-       dev->fmt_idx = get_resolution_index(fmt->width, fmt->height);
-       if (dev->fmt_idx == -1) {
-               dev_err(&client->dev, "get resolution fail\n");
-               mutex_unlock(&dev->input_lock);
-               return -EINVAL;
-       }
-
-       ret = startup(sd);
-       if (ret) {
-               dev_err(&client->dev, "gc2235 startup err\n");
-               goto err;
-       }
-
-       ret = gc2235_get_intg_factor(client, gc2235_info,
-                                    &gc2235_res[dev->fmt_idx]);
-       if (ret)
-               dev_err(&client->dev, "failed to get integration_factor\n");
-
-err:
-       mutex_unlock(&dev->input_lock);
-       return ret;
-}
-
-static int gc2235_get_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
-                         struct v4l2_subdev_format *format)
-{
-       struct v4l2_mbus_framefmt *fmt = &format->format;
-       struct gc2235_device *dev = to_gc2235_sensor(sd);
-
-       if (format->pad)
-               return -EINVAL;
-
-       if (!fmt)
-               return -EINVAL;
-
-       fmt->width = gc2235_res[dev->fmt_idx].width;
-       fmt->height = gc2235_res[dev->fmt_idx].height;
-       fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
-
-       return 0;
-}
-
-static int gc2235_detect(struct i2c_client *client)
-{
-       struct i2c_adapter *adapter = client->adapter;
-       u16 high, low;
-       int ret;
-       u16 id;
-
-       if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
-               return -ENODEV;
-
-       ret = gc2235_read_reg(client, GC2235_8BIT,
-                                       GC2235_SENSOR_ID_H, &high);
-       if (ret) {
-               dev_err(&client->dev, "sensor_id_high = 0x%x\n", high);
-               return -ENODEV;
-       }
-       ret = gc2235_read_reg(client, GC2235_8BIT,
-                                       GC2235_SENSOR_ID_L, &low);
-       id = ((high << 8) | low);
-
-       if (id != GC2235_ID) {
-               dev_err(&client->dev, "sensor ID error, 0x%x\n", id);
-               return -ENODEV;
-       }
-
-       dev_info(&client->dev, "detect gc2235 success\n");
-       return 0;
-}
-
-static int gc2235_s_stream(struct v4l2_subdev *sd, int enable)
-{
-       struct gc2235_device *dev = to_gc2235_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret;
-       mutex_lock(&dev->input_lock);
-
-       if (enable)
-               ret = gc2235_write_reg_array(client, gc2235_stream_on);
-       else
-               ret = gc2235_write_reg_array(client, gc2235_stream_off);
-
-       mutex_unlock(&dev->input_lock);
-       return ret;
-}
-
-
-static int gc2235_s_config(struct v4l2_subdev *sd,
-                          int irq, void *platform_data)
-{
-       struct gc2235_device *dev = to_gc2235_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret = 0;
-
-       if (!platform_data)
-               return -ENODEV;
-
-       dev->platform_data =
-               (struct camera_sensor_platform_data *)platform_data;
-
-       mutex_lock(&dev->input_lock);
-       if (dev->platform_data->platform_init) {
-               ret = dev->platform_data->platform_init(client);
-               if (ret) {
-                       dev_err(&client->dev, "platform init err\n");
-                       goto platform_init_failed;
-               }
-       }
-       /* power off the module, then power on it in future
-        * as first power on by board may not fulfill the
-        * power on sequqence needed by the module
-        */
-       ret = power_down(sd);
-       if (ret) {
-               dev_err(&client->dev, "gc2235 power-off err.\n");
-               goto fail_power_off;
-       }
-
-       ret = power_up(sd);
-       if (ret) {
-               dev_err(&client->dev, "gc2235 power-up err.\n");
-               goto fail_power_on;
-       }
-
-       ret = dev->platform_data->csi_cfg(sd, 1);
-       if (ret)
-               goto fail_csi_cfg;
-
-       /* config & detect sensor */
-       ret = gc2235_detect(client);
-       if (ret) {
-               dev_err(&client->dev, "gc2235_detect err s_config.\n");
-               goto fail_csi_cfg;
-       }
-
-       /* turn off sensor, after probed */
-       ret = power_down(sd);
-       if (ret) {
-               dev_err(&client->dev, "gc2235 power-off err.\n");
-               goto fail_csi_cfg;
-       }
-       mutex_unlock(&dev->input_lock);
-
-       return 0;
-
-fail_csi_cfg:
-       dev->platform_data->csi_cfg(sd, 0);
-fail_power_on:
-       power_down(sd);
-       dev_err(&client->dev, "sensor power-gating failed\n");
-fail_power_off:
-       if (dev->platform_data->platform_deinit)
-               dev->platform_data->platform_deinit();
-platform_init_failed:
-       mutex_unlock(&dev->input_lock);
-       return ret;
-}
-
-static int gc2235_g_parm(struct v4l2_subdev *sd,
-                       struct v4l2_streamparm *param)
-{
-       struct gc2235_device *dev = to_gc2235_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (!param)
-               return -EINVAL;
-
-       if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-               dev_err(&client->dev,  "unsupported buffer type.\n");
-               return -EINVAL;
-       }
-
-       memset(param, 0, sizeof(*param));
-       param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-       if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) {
-               param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
-               param->parm.capture.timeperframe.numerator = 1;
-               param->parm.capture.capturemode = dev->run_mode;
-               param->parm.capture.timeperframe.denominator =
-                       gc2235_res[dev->fmt_idx].fps;
-       }
-       return 0;
-}
-
-static int gc2235_s_parm(struct v4l2_subdev *sd,
-                       struct v4l2_streamparm *param)
-{
-       struct gc2235_device *dev = to_gc2235_sensor(sd);
-       dev->run_mode = param->parm.capture.capturemode;
-
-       mutex_lock(&dev->input_lock);
-       switch (dev->run_mode) {
-       case CI_MODE_VIDEO:
-               gc2235_res = gc2235_res_video;
-               N_RES = N_RES_VIDEO;
-               break;
-       case CI_MODE_STILL_CAPTURE:
-               gc2235_res = gc2235_res_still;
-               N_RES = N_RES_STILL;
-               break;
-       default:
-               gc2235_res = gc2235_res_preview;
-               N_RES = N_RES_PREVIEW;
-       }
-       mutex_unlock(&dev->input_lock);
-       return 0;
-}
-
-static int gc2235_g_frame_interval(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_frame_interval *interval)
-{
-       struct gc2235_device *dev = to_gc2235_sensor(sd);
-
-       interval->interval.numerator = 1;
-       interval->interval.denominator = gc2235_res[dev->fmt_idx].fps;
-
-       return 0;
-}
-
-static int gc2235_enum_mbus_code(struct v4l2_subdev *sd,
-                               struct v4l2_subdev_pad_config *cfg,
-                               struct v4l2_subdev_mbus_code_enum *code)
-{
-       if (code->index >= MAX_FMTS)
-               return -EINVAL;
-
-       code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
-       return 0;
-}
-
-static int gc2235_enum_frame_size(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
-                                 struct v4l2_subdev_frame_size_enum *fse)
-{
-       int index = fse->index;
-
-       if (index >= N_RES)
-               return -EINVAL;
-
-       fse->min_width = gc2235_res[index].width;
-       fse->min_height = gc2235_res[index].height;
-       fse->max_width = gc2235_res[index].width;
-       fse->max_height = gc2235_res[index].height;
-
-       return 0;
-
-}
-
-static int gc2235_g_skip_frames(struct v4l2_subdev *sd, u32 *frames)
-{
-       struct gc2235_device *dev = to_gc2235_sensor(sd);
-
-       mutex_lock(&dev->input_lock);
-       *frames = gc2235_res[dev->fmt_idx].skip_frames;
-       mutex_unlock(&dev->input_lock);
-
-       return 0;
-}
-
-static const struct v4l2_subdev_sensor_ops gc2235_sensor_ops = {
-       .g_skip_frames  = gc2235_g_skip_frames,
-};
-
-static const struct v4l2_subdev_video_ops gc2235_video_ops = {
-       .s_stream = gc2235_s_stream,
-       .g_parm = gc2235_g_parm,
-       .s_parm = gc2235_s_parm,
-       .g_frame_interval = gc2235_g_frame_interval,
-};
-
-static const struct v4l2_subdev_core_ops gc2235_core_ops = {
-       .s_power = gc2235_s_power,
-       .ioctl = gc2235_ioctl,
-};
-
-static const struct v4l2_subdev_pad_ops gc2235_pad_ops = {
-       .enum_mbus_code = gc2235_enum_mbus_code,
-       .enum_frame_size = gc2235_enum_frame_size,
-       .get_fmt = gc2235_get_fmt,
-       .set_fmt = gc2235_set_fmt,
-};
-
-static const struct v4l2_subdev_ops gc2235_ops = {
-       .core = &gc2235_core_ops,
-       .video = &gc2235_video_ops,
-       .pad = &gc2235_pad_ops,
-       .sensor = &gc2235_sensor_ops,
-};
-
-static int gc2235_remove(struct i2c_client *client)
-{
-       struct v4l2_subdev *sd = i2c_get_clientdata(client);
-       struct gc2235_device *dev = to_gc2235_sensor(sd);
-       dev_dbg(&client->dev, "gc2235_remove...\n");
-
-       if (dev->platform_data->platform_deinit)
-               dev->platform_data->platform_deinit();
-
-       dev->platform_data->csi_cfg(sd, 0);
-
-       v4l2_device_unregister_subdev(sd);
-       media_entity_cleanup(&dev->sd.entity);
-       v4l2_ctrl_handler_free(&dev->ctrl_handler);
-       kfree(dev);
-
-       return 0;
-}
-
-static int gc2235_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
-{
-       struct gc2235_device *dev;
-       void *gcpdev;
-       int ret;
-       unsigned int i;
-
-       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-       if (!dev) {
-               dev_err(&client->dev, "out of memory\n");
-               return -ENOMEM;
-       }
-
-       mutex_init(&dev->input_lock);
-
-       dev->fmt_idx = 0;
-       v4l2_i2c_subdev_init(&(dev->sd), client, &gc2235_ops);
-
-       gcpdev = client->dev.platform_data;
-       if (ACPI_COMPANION(&client->dev))
-               gcpdev = gmin_camera_platform_data(&dev->sd,
-                                  ATOMISP_INPUT_FORMAT_RAW_10,
-                                  atomisp_bayer_order_grbg);
-
-       ret = gc2235_s_config(&dev->sd, client->irq, gcpdev);
-       if (ret)
-               goto out_free;
-
-       dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-       dev->pad.flags = MEDIA_PAD_FL_SOURCE;
-       dev->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
-       dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
-       ret =
-           v4l2_ctrl_handler_init(&dev->ctrl_handler,
-                                  ARRAY_SIZE(gc2235_controls));
-       if (ret) {
-               gc2235_remove(client);
-               return ret;
-       }
-
-       for (i = 0; i < ARRAY_SIZE(gc2235_controls); i++)
-               v4l2_ctrl_new_custom(&dev->ctrl_handler, &gc2235_controls[i],
-                                    NULL);
-
-       if (dev->ctrl_handler.error) {
-               gc2235_remove(client);
-               return dev->ctrl_handler.error;
-       }
-
-       /* Use same lock for controls as for everything else. */
-       dev->ctrl_handler.lock = &dev->input_lock;
-       dev->sd.ctrl_handler = &dev->ctrl_handler;
-
-       ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad);
-       if (ret)
-               gc2235_remove(client);
-
-       if (ACPI_HANDLE(&client->dev))
-               ret = atomisp_register_i2c_module(&dev->sd, gcpdev, RAW_CAMERA);
-
-       return ret;
-out_free:
-       v4l2_device_unregister_subdev(&dev->sd);
-       kfree(dev);
-
-       return ret;
-}
-
-static const struct acpi_device_id gc2235_acpi_match[] = {
-       { "INT33F8" },
-       {},
-};
-
-MODULE_DEVICE_TABLE(acpi, gc2235_acpi_match);
-MODULE_DEVICE_TABLE(i2c, gc2235_id);
-static struct i2c_driver gc2235_driver = {
-       .driver = {
-               .name = GC2235_NAME,
-               .acpi_match_table = ACPI_PTR(gc2235_acpi_match),
-       },
-       .probe = gc2235_probe,
-       .remove = gc2235_remove,
-       .id_table = gc2235_id,
-};
-
-static int init_gc2235(void)
-{
-       return i2c_add_driver(&gc2235_driver);
-}
-
-static void exit_gc2235(void)
-{
-
-       i2c_del_driver(&gc2235_driver);
-}
-
-module_init(init_gc2235);
-module_exit(exit_gc2235);
-
-MODULE_AUTHOR("Shuguang Gong <Shuguang.Gong@intel.com>");
-MODULE_DESCRIPTION("A low-level driver for GC2235 sensors");
-MODULE_LICENSE("GPL");
index a39eeb3b6ad43a06ebce916f89162d313290632e..c4356c1a8aca7b9f8e866a1e121a9edc04b5f6d7 100644 (file)
@@ -1,6 +1,6 @@
-config VIDEO_IMX
+config VIDEO_ATOMISP_IMX
        tristate "sony imx sensor support"
-       depends on I2C && VIDEO_V4L2 && VIDEO_MSRLIST_HELPER && m
+       depends on I2C && VIDEO_V4L2 && VIDEO_ATOMISP_MSRLIST_HELPER && m
        ---help---
          This is a Video4Linux2 sensor-level driver for the Sony
          IMX RAW sensor.
index b6578f09546ee32ec20f9c060434962396e0f64a..f3e2891cdfecd2c9032c4ccffd9c95d07a437ec9 100644 (file)
@@ -1,9 +1,9 @@
-obj-$(CONFIG_VIDEO_IMX) += imx1x5.o
+obj-$(CONFIG_VIDEO_ATOMISP_IMX) += atomisp-imx1x5.o
 
-imx1x5-objs := imx.o drv201.o ad5816g.o dw9714.o dw9719.o dw9718.o vcm.o otp.o otp_imx.o otp_brcc064_e2prom.o otp_e2prom.o
+atomisp-imx1x5-objs := imx.o drv201.o ad5816g.o dw9714.o dw9719.o dw9718.o vcm.o otp.o otp_imx.o otp_brcc064_e2prom.o otp_e2prom.o
 
-ov8858_driver-objs := ../ov8858.o dw9718.o vcm.o
-obj-$(CONFIG_VIDEO_OV8858)     += ov8858_driver.o
+atomisp-ov8858-objs := ../ov8858.o dw9718.o vcm.o
+obj-$(CONFIG_VIDEO_ATOMISP_OV8858)     += atomisp-ov8858.o
 
 # HACK! While this driver is in bad shape, don't enable several warnings
 #       that would be otherwise enabled with W=1
diff --git a/drivers/staging/media/atomisp/i2c/libmsrlisthelper.c b/drivers/staging/media/atomisp/i2c/libmsrlisthelper.c
deleted file mode 100644 (file)
index decb65c..0000000
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright (c) 2013 Intel Corporation. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- */
-#include <linux/i2c.h>
-#include <linux/firmware.h>
-#include <linux/device.h>
-#include <linux/export.h>
-#include "../include/linux/libmsrlisthelper.h"
-#include <linux/module.h>
-#include <linux/slab.h>
-
-/* Tagged binary data container structure definitions. */
-struct tbd_header {
-       uint32_t tag;          /*!< Tag identifier, also checks endianness */
-       uint32_t size;         /*!< Container size including this header */
-       uint32_t version;      /*!< Version, format 0xYYMMDDVV */
-       uint32_t revision;     /*!< Revision, format 0xYYMMDDVV */
-       uint32_t config_bits;  /*!< Configuration flag bits set */
-       uint32_t checksum;     /*!< Global checksum, header included */
-} __packed;
-
-struct tbd_record_header {
-       uint32_t size;        /*!< Size of record including header */
-       uint8_t format_id;    /*!< tbd_format_t enumeration values used */
-       uint8_t packing_key;  /*!< Packing method; 0 = no packing */
-       uint16_t class_id;    /*!< tbd_class_t enumeration values used */
-} __packed;
-
-struct tbd_data_record_header {
-       uint16_t next_offset;
-       uint16_t flags;
-       uint16_t data_offset;
-       uint16_t data_size;
-} __packed;
-
-#define TBD_CLASS_DRV_ID 2
-
-static int set_msr_configuration(struct i2c_client *client, uint8_t *bufptr,
-               unsigned int size)
-{
-       /* The configuration data contains any number of sequences where
-        * the first byte (that is, uint8_t) that marks the number of bytes
-        * in the sequence to follow, is indeed followed by the indicated
-        * number of bytes of actual data to be written to sensor.
-        * By convention, the first two bytes of actual data should be
-        * understood as an address in the sensor address space (hibyte
-        * followed by lobyte) where the remaining data in the sequence
-        * will be written. */
-
-       uint8_t *ptr = bufptr;
-       while (ptr < bufptr + size) {
-               struct i2c_msg msg = {
-                       .addr = client->addr,
-                       .flags = 0,
-               };
-               int ret;
-
-               /* How many bytes */
-               msg.len = *ptr++;
-               /* Where the bytes are located */
-               msg.buf = ptr;
-               ptr += msg.len;
-
-               if (ptr > bufptr + size)
-                       /* Accessing data beyond bounds is not tolerated */
-                       return -EINVAL;
-
-               ret = i2c_transfer(client->adapter, &msg, 1);
-               if (ret < 0) {
-                       dev_err(&client->dev, "i2c write error: %d", ret);
-                       return ret;
-               }
-       }
-       return 0;
-}
-
-static int parse_and_apply(struct i2c_client *client, uint8_t *buffer,
-               unsigned int size)
-{
-       uint8_t *endptr8 = buffer + size;
-       struct tbd_data_record_header *header =
-               (struct tbd_data_record_header *)buffer;
-
-       /* There may be any number of datasets present */
-       unsigned int dataset = 0;
-
-       do {
-               /* In below, four variables are read from buffer */
-               if ((uint8_t *)header + sizeof(*header) > endptr8)
-                       return -EINVAL;
-
-               /* All data should be located within given buffer */
-               if ((uint8_t *)header + header->data_offset +
-                               header->data_size > endptr8)
-                       return -EINVAL;
-
-               /* We have a new valid dataset */
-               dataset++;
-               /* See whether there is MSR data */
-               /* If yes, update the reg info */
-               if (header->data_size && (header->flags & 1)) {
-                       int ret;
-
-                       dev_info(&client->dev,
-                               "New MSR data for sensor driver (dataset %02d) size:%d\n",
-                               dataset, header->data_size);
-                       ret = set_msr_configuration(client,
-                                               buffer + header->data_offset,
-                                               header->data_size);
-                       if (ret)
-                               return ret;
-               }
-               header = (struct tbd_data_record_header *)(buffer +
-                       header->next_offset);
-       } while (header->next_offset);
-
-       return 0;
-}
-
-int apply_msr_data(struct i2c_client *client, const struct firmware *fw)
-{
-       struct tbd_header *header;
-       struct tbd_record_header *record;
-
-       if (!fw) {
-               dev_warn(&client->dev, "Drv data is not loaded.\n");
-               return -EINVAL;
-       }
-
-       if (sizeof(*header) > fw->size)
-               return -EINVAL;
-
-       header = (struct tbd_header *)fw->data;
-       /* Check that we have drvb block. */
-       if (memcmp(&header->tag, "DRVB", 4))
-               return -EINVAL;
-
-       /* Check the size */
-       if (header->size != fw->size)
-               return -EINVAL;
-
-       if (sizeof(*header) + sizeof(*record) > fw->size)
-               return -EINVAL;
-
-       record = (struct tbd_record_header *)(header + 1);
-       /* Check that class id mathes tbd's drv id. */
-       if (record->class_id != TBD_CLASS_DRV_ID)
-               return -EINVAL;
-
-       /* Size 0 shall not be treated as an error */
-       if (!record->size)
-               return 0;
-
-       return parse_and_apply(client, (uint8_t *)(record + 1), record->size);
-}
-EXPORT_SYMBOL_GPL(apply_msr_data);
-
-int load_msr_list(struct i2c_client *client, char *name,
-               const struct firmware **fw)
-{
-       int ret = request_firmware(fw, name, &client->dev);
-       if (ret) {
-               dev_err(&client->dev,
-                       "Error %d while requesting firmware %s\n",
-                       ret, name);
-               return ret;
-       }
-       dev_info(&client->dev, "Received %lu bytes drv data\n",
-                       (unsigned long)(*fw)->size);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(load_msr_list);
-
-void release_msr_list(struct i2c_client *client, const struct firmware *fw)
-{
-       release_firmware(fw);
-}
-EXPORT_SYMBOL_GPL(release_msr_list);
-
-static int init_msrlisthelper(void)
-{
-       return 0;
-}
-
-static void exit_msrlisthelper(void)
-{
-}
-
-module_init(init_msrlisthelper);
-module_exit(exit_msrlisthelper);
-
-MODULE_AUTHOR("Jukka Kaartinen <jukka.o.kaartinen@intel.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/media/atomisp/i2c/lm3554.c b/drivers/staging/media/atomisp/i2c/lm3554.c
deleted file mode 100644 (file)
index 679176f..0000000
+++ /dev/null
@@ -1,1009 +0,0 @@
-/*
- * LED flash driver for LM3554
- *
- * Copyright (c) 2010-2012 Intel Corporation. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- */
-#include <linux/module.h>
-#include <linux/i2c.h>
-#include <linux/mutex.h>
-#include <linux/delay.h>
-#include <linux/gpio.h>
-#include <linux/slab.h>
-
-#include "../include/media/lm3554.h"
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-device.h>
-#include <linux/acpi.h>
-#include <linux/gpio/consumer.h>
-#include "../include/linux/atomisp_gmin_platform.h"
-#include "../include/linux/atomisp.h"
-
-/* Registers */
-
-#define LM3554_TORCH_BRIGHTNESS_REG    0xA0
-#define LM3554_TORCH_MODE_SHIFT                0
-#define LM3554_TORCH_CURRENT_SHIFT     3
-#define LM3554_INDICATOR_CURRENT_SHIFT 6
-
-#define LM3554_FLASH_BRIGHTNESS_REG    0xB0
-#define LM3554_FLASH_MODE_SHIFT                0
-#define LM3554_FLASH_CURRENT_SHIFT     3
-#define LM3554_STROBE_SENSITIVITY_SHIFT        7
-
-#define LM3554_FLASH_DURATION_REG      0xC0
-#define LM3554_FLASH_TIMEOUT_SHIFT     0
-#define LM3554_CURRENT_LIMIT_SHIFT     5
-
-#define LM3554_FLAGS_REG               0xD0
-#define LM3554_FLAG_TIMEOUT            (1 << 0)
-#define LM3554_FLAG_THERMAL_SHUTDOWN   (1 << 1)
-#define LM3554_FLAG_LED_FAULT          (1 << 2)
-#define LM3554_FLAG_TX1_INTERRUPT      (1 << 3)
-#define LM3554_FLAG_TX2_INTERRUPT      (1 << 4)
-#define LM3554_FLAG_LED_THERMAL_FAULT  (1 << 5)
-#define LM3554_FLAG_UNUSED             (1 << 6)
-#define LM3554_FLAG_INPUT_VOLTAGE_LOW  (1 << 7)
-
-#define LM3554_CONFIG_REG_1            0xE0
-#define LM3554_ENVM_TX2_SHIFT          5
-#define LM3554_TX2_POLARITY_SHIFT      6
-
-struct lm3554 {
-       struct v4l2_subdev sd;
-
-       struct mutex power_lock;
-       struct v4l2_ctrl_handler ctrl_handler;
-       int power_count;
-
-       unsigned int mode;
-       int timeout;
-       u8 torch_current;
-       u8 indicator_current;
-       u8 flash_current;
-
-       struct timer_list flash_off_delay;
-       struct lm3554_platform_data *pdata;
-};
-
-#define to_lm3554(p_sd)        container_of(p_sd, struct lm3554, sd)
-
-/* Return negative errno else zero on success */
-static int lm3554_write(struct lm3554 *flash, u8 addr, u8 val)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(&flash->sd);
-       int ret;
-
-       ret = i2c_smbus_write_byte_data(client, addr, val);
-
-       dev_dbg(&client->dev, "Write Addr:%02X Val:%02X %s\n", addr, val,
-               ret < 0 ? "fail" : "ok");
-
-       return ret;
-}
-
-/* Return negative errno else a data byte received from the device. */
-static int lm3554_read(struct lm3554 *flash, u8 addr)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(&flash->sd);
-       int ret;
-
-       ret = i2c_smbus_read_byte_data(client, addr);
-
-       dev_dbg(&client->dev, "Read Addr:%02X Val:%02X %s\n", addr, ret,
-               ret < 0 ? "fail" : "ok");
-
-       return ret;
-}
-
-/* -----------------------------------------------------------------------------
- * Hardware configuration
- */
-
-static int lm3554_set_mode(struct lm3554 *flash, unsigned int mode)
-{
-       u8 val;
-       int ret;
-
-       val = (mode << LM3554_FLASH_MODE_SHIFT) |
-             (flash->flash_current << LM3554_FLASH_CURRENT_SHIFT);
-
-       ret = lm3554_write(flash, LM3554_FLASH_BRIGHTNESS_REG, val);
-       if (ret == 0)
-               flash->mode = mode;
-       return ret;
-}
-
-static int lm3554_set_torch(struct lm3554 *flash)
-{
-       u8 val;
-
-       val = (flash->mode << LM3554_TORCH_MODE_SHIFT) |
-             (flash->torch_current << LM3554_TORCH_CURRENT_SHIFT) |
-             (flash->indicator_current << LM3554_INDICATOR_CURRENT_SHIFT);
-
-       return lm3554_write(flash, LM3554_TORCH_BRIGHTNESS_REG, val);
-}
-
-static int lm3554_set_flash(struct lm3554 *flash)
-{
-       u8 val;
-
-       val = (flash->mode << LM3554_FLASH_MODE_SHIFT) |
-             (flash->flash_current << LM3554_FLASH_CURRENT_SHIFT);
-
-       return lm3554_write(flash, LM3554_FLASH_BRIGHTNESS_REG, val);
-}
-
-static int lm3554_set_duration(struct lm3554 *flash)
-{
-       u8 val;
-
-       val = (flash->timeout << LM3554_FLASH_TIMEOUT_SHIFT) |
-             (flash->pdata->current_limit << LM3554_CURRENT_LIMIT_SHIFT);
-
-       return lm3554_write(flash, LM3554_FLASH_DURATION_REG, val);
-}
-
-static int lm3554_set_config1(struct lm3554 *flash)
-{
-       u8 val;
-
-       val = (flash->pdata->envm_tx2 << LM3554_ENVM_TX2_SHIFT) |
-             (flash->pdata->tx2_polarity << LM3554_TX2_POLARITY_SHIFT);
-       return lm3554_write(flash, LM3554_CONFIG_REG_1, val);
-}
-
-/* -----------------------------------------------------------------------------
- * Hardware trigger
- */
-static void lm3554_flash_off_delay(long unsigned int arg)
-{
-       struct v4l2_subdev *sd = i2c_get_clientdata((struct i2c_client *)arg);
-       struct lm3554 *flash = to_lm3554(sd);
-       struct lm3554_platform_data *pdata = flash->pdata;
-
-       gpio_set_value(pdata->gpio_strobe, 0);
-}
-
-static int lm3554_hw_strobe(struct i2c_client *client, bool strobe)
-{
-       int ret, timer_pending;
-       struct v4l2_subdev *sd = i2c_get_clientdata(client);
-       struct lm3554 *flash = to_lm3554(sd);
-       struct lm3554_platform_data *pdata = flash->pdata;
-
-       /*
-        * An abnormal high flash current is observed when strobe off the
-        * flash. Workaround here is firstly set flash current to lower level,
-        * wait a short moment, and then strobe off the flash.
-        */
-
-       timer_pending = del_timer_sync(&flash->flash_off_delay);
-
-       /* Flash off */
-       if (!strobe) {
-               /* set current to 70mA and wait a while */
-               ret = lm3554_write(flash, LM3554_FLASH_BRIGHTNESS_REG, 0);
-               if (ret < 0)
-                       goto err;
-               mod_timer(&flash->flash_off_delay,
-                         jiffies + msecs_to_jiffies(LM3554_TIMER_DELAY));
-               return 0;
-       }
-
-       /* Flash on */
-
-       /*
-        * If timer is killed before run, flash is not strobe off,
-        * so must strobe off here
-        */
-       if (timer_pending)
-               gpio_set_value(pdata->gpio_strobe, 0);
-
-       /* Restore flash current settings */
-       ret = lm3554_set_flash(flash);
-       if (ret < 0)
-               goto err;
-
-       /* Strobe on Flash */
-       gpio_set_value(pdata->gpio_strobe, 1);
-
-       return 0;
-err:
-       dev_err(&client->dev, "failed to %s flash strobe (%d)\n",
-               strobe ? "on" : "off", ret);
-       return ret;
-}
-
-/* -----------------------------------------------------------------------------
- * V4L2 controls
- */
-
-static int lm3554_read_status(struct lm3554 *flash)
-{
-       int ret;
-       struct i2c_client *client = v4l2_get_subdevdata(&flash->sd);
-
-       /* NOTE: reading register clear fault status */
-       ret = lm3554_read(flash, LM3554_FLAGS_REG);
-       if (ret < 0)
-               return ret;
-
-       /*
-        * Accordingly to datasheet we read back '1' in bit 6.
-        * Clear it first.
-        */
-       ret &= ~LM3554_FLAG_UNUSED;
-
-       /*
-        * Do not take TX1/TX2 signal as an error
-        * because MSIC will not turn off flash, but turn to
-        * torch mode according to gsm modem signal by hardware.
-        */
-       ret &= ~(LM3554_FLAG_TX1_INTERRUPT | LM3554_FLAG_TX2_INTERRUPT);
-
-       if (ret > 0)
-               dev_dbg(&client->dev, "LM3554 flag status: %02x\n", ret);
-
-       return ret;
-}
-
-static int lm3554_s_flash_timeout(struct v4l2_subdev *sd, u32 val)
-{
-       struct lm3554 *flash = to_lm3554(sd);
-
-       val = clamp(val, LM3554_MIN_TIMEOUT, LM3554_MAX_TIMEOUT);
-       val = val / LM3554_TIMEOUT_STEPSIZE - 1;
-
-       flash->timeout = val;
-
-       return lm3554_set_duration(flash);
-}
-
-static int lm3554_g_flash_timeout(struct v4l2_subdev *sd, s32 *val)
-{
-       struct lm3554 *flash = to_lm3554(sd);
-
-       *val = (u32)(flash->timeout + 1) * LM3554_TIMEOUT_STEPSIZE;
-
-       return 0;
-}
-
-static int lm3554_s_flash_intensity(struct v4l2_subdev *sd, u32 intensity)
-{
-       struct lm3554 *flash = to_lm3554(sd);
-
-       intensity = LM3554_CLAMP_PERCENTAGE(intensity);
-       intensity = LM3554_PERCENT_TO_VALUE(intensity, LM3554_FLASH_STEP);
-
-       flash->flash_current = intensity;
-
-       return lm3554_set_flash(flash);
-}
-
-static int lm3554_g_flash_intensity(struct v4l2_subdev *sd, s32 *val)
-{
-       struct lm3554 *flash = to_lm3554(sd);
-
-       *val = LM3554_VALUE_TO_PERCENT((u32)flash->flash_current,
-                       LM3554_FLASH_STEP);
-
-       return 0;
-}
-
-static int lm3554_s_torch_intensity(struct v4l2_subdev *sd, u32 intensity)
-{
-       struct lm3554 *flash = to_lm3554(sd);
-
-       intensity = LM3554_CLAMP_PERCENTAGE(intensity);
-       intensity = LM3554_PERCENT_TO_VALUE(intensity, LM3554_TORCH_STEP);
-
-       flash->torch_current = intensity;
-
-       return lm3554_set_torch(flash);
-}
-
-static int lm3554_g_torch_intensity(struct v4l2_subdev *sd, s32 *val)
-{
-       struct lm3554 *flash = to_lm3554(sd);
-
-       *val = LM3554_VALUE_TO_PERCENT((u32)flash->torch_current,
-                       LM3554_TORCH_STEP);
-
-       return 0;
-}
-
-static int lm3554_s_indicator_intensity(struct v4l2_subdev *sd, u32 intensity)
-{
-       struct lm3554 *flash = to_lm3554(sd);
-
-       intensity = LM3554_CLAMP_PERCENTAGE(intensity);
-       intensity = LM3554_PERCENT_TO_VALUE(intensity, LM3554_INDICATOR_STEP);
-
-       flash->indicator_current = intensity;
-
-       return lm3554_set_torch(flash);
-}
-
-static int lm3554_g_indicator_intensity(struct v4l2_subdev *sd, s32 *val)
-{
-       struct lm3554 *flash = to_lm3554(sd);
-
-       *val = LM3554_VALUE_TO_PERCENT((u32)flash->indicator_current,
-                       LM3554_INDICATOR_STEP);
-
-       return 0;
-}
-
-static int lm3554_s_flash_strobe(struct v4l2_subdev *sd, u32 val)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return lm3554_hw_strobe(client, val);
-}
-
-static int lm3554_s_flash_mode(struct v4l2_subdev *sd, u32 new_mode)
-{
-       struct lm3554 *flash = to_lm3554(sd);
-       unsigned int mode;
-
-       switch (new_mode) {
-       case ATOMISP_FLASH_MODE_OFF:
-               mode = LM3554_MODE_SHUTDOWN;
-               break;
-       case ATOMISP_FLASH_MODE_FLASH:
-               mode = LM3554_MODE_FLASH;
-               break;
-       case ATOMISP_FLASH_MODE_INDICATOR:
-               mode = LM3554_MODE_INDICATOR;
-               break;
-       case ATOMISP_FLASH_MODE_TORCH:
-               mode = LM3554_MODE_TORCH;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return lm3554_set_mode(flash, mode);
-}
-
-static int lm3554_g_flash_mode(struct v4l2_subdev *sd, s32 *val)
-{
-       struct lm3554 *flash = to_lm3554(sd);
-       *val = flash->mode;
-       return 0;
-}
-
-static int lm3554_g_flash_status(struct v4l2_subdev *sd, s32 *val)
-{
-       struct lm3554 *flash = to_lm3554(sd);
-       int value;
-
-       value = lm3554_read_status(flash);
-       if (value < 0)
-               return value;
-
-       if (value & LM3554_FLAG_TIMEOUT)
-               *val = ATOMISP_FLASH_STATUS_TIMEOUT;
-       else if (value > 0)
-               *val = ATOMISP_FLASH_STATUS_HW_ERROR;
-       else
-               *val = ATOMISP_FLASH_STATUS_OK;
-
-       return 0;
-}
-
-#ifndef CSS15
-static int lm3554_g_flash_status_register(struct v4l2_subdev *sd, s32 *val)
-{
-       struct lm3554 *flash = to_lm3554(sd);
-       int ret;
-
-       ret = lm3554_read(flash, LM3554_FLAGS_REG);
-
-       if (ret < 0)
-               return ret;
-
-       *val = ret;
-       return 0;
-}
-#endif
-
-static int lm3554_s_ctrl(struct v4l2_ctrl *ctrl)
-{
-       struct lm3554 *dev =
-           container_of(ctrl->handler, struct lm3554, ctrl_handler);
-       int ret = 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_FLASH_TIMEOUT:
-               ret = lm3554_s_flash_timeout(&dev->sd, ctrl->val);
-               break;
-       case V4L2_CID_FLASH_INTENSITY:
-               ret = lm3554_s_flash_intensity(&dev->sd, ctrl->val);
-               break;
-       case V4L2_CID_FLASH_TORCH_INTENSITY:
-               ret = lm3554_s_torch_intensity(&dev->sd, ctrl->val);
-               break;
-       case V4L2_CID_FLASH_INDICATOR_INTENSITY:
-               ret = lm3554_s_indicator_intensity(&dev->sd, ctrl->val);
-               break;
-       case V4L2_CID_FLASH_STROBE:
-               ret = lm3554_s_flash_strobe(&dev->sd, ctrl->val);
-               break;
-       case V4L2_CID_FLASH_MODE:
-               ret = lm3554_s_flash_mode(&dev->sd, ctrl->val);
-               break;
-       default:
-               ret = -EINVAL;
-       }
-       return ret;
-}
-
-static int lm3554_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
-{
-       struct lm3554 *dev =
-           container_of(ctrl->handler, struct lm3554, ctrl_handler);
-       int ret = 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_FLASH_TIMEOUT:
-               ret = lm3554_g_flash_timeout(&dev->sd, &ctrl->val);
-               break;
-       case V4L2_CID_FLASH_INTENSITY:
-               ret = lm3554_g_flash_intensity(&dev->sd, &ctrl->val);
-               break;
-       case V4L2_CID_FLASH_TORCH_INTENSITY:
-               ret = lm3554_g_torch_intensity(&dev->sd, &ctrl->val);
-               break;
-       case V4L2_CID_FLASH_INDICATOR_INTENSITY:
-               ret = lm3554_g_indicator_intensity(&dev->sd, &ctrl->val);
-               break;
-       case V4L2_CID_FLASH_MODE:
-               ret = lm3554_g_flash_mode(&dev->sd, &ctrl->val);
-               break;
-       case V4L2_CID_FLASH_STATUS:
-               ret = lm3554_g_flash_status(&dev->sd, &ctrl->val);
-               break;
-#ifndef CSS15
-       case V4L2_CID_FLASH_STATUS_REGISTER:
-               ret = lm3554_g_flash_status_register(&dev->sd, &ctrl->val);
-               break;
-#endif
-       default:
-               ret = -EINVAL;
-       }
-
-       return ret;
-}
-
-static const struct v4l2_ctrl_ops ctrl_ops = {
-       .s_ctrl = lm3554_s_ctrl,
-       .g_volatile_ctrl = lm3554_g_volatile_ctrl
-};
-
-static const struct v4l2_ctrl_config lm3554_controls[] = {
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_FLASH_TIMEOUT,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .name = "Flash Timeout",
-        .min = 0x0,
-        .max = LM3554_MAX_TIMEOUT,
-        .step = 0x01,
-        .def = LM3554_DEFAULT_TIMEOUT,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_FLASH_INTENSITY,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .name = "Flash Intensity",
-        .min = LM3554_MIN_PERCENT,
-        .max = LM3554_MAX_PERCENT,
-        .step = 0x01,
-        .def = LM3554_FLASH_DEFAULT_BRIGHTNESS,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_FLASH_TORCH_INTENSITY,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .name = "Torch Intensity",
-        .min = LM3554_MIN_PERCENT,
-        .max = LM3554_MAX_PERCENT,
-        .step = 0x01,
-        .def = LM3554_TORCH_DEFAULT_BRIGHTNESS,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_FLASH_INDICATOR_INTENSITY,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .name = "Indicator Intensity",
-        .min = LM3554_MIN_PERCENT,
-        .max = LM3554_MAX_PERCENT,
-        .step = 0x01,
-        .def = LM3554_INDICATOR_DEFAULT_BRIGHTNESS,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_FLASH_STROBE,
-        .type = V4L2_CTRL_TYPE_BOOLEAN,
-        .name = "Flash Strobe",
-        .min = 0,
-        .max = 1,
-        .step = 1,
-        .def = 0,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_FLASH_MODE,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .name = "Flash Mode",
-        .min = 0,
-        .max = 100,
-        .step = 1,
-        .def = ATOMISP_FLASH_MODE_OFF,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_FLASH_STATUS,
-        .type = V4L2_CTRL_TYPE_BOOLEAN,
-        .name = "Flash Status",
-        .min = 0,
-        .max = 100,
-        .step = 1,
-        .def = ATOMISP_FLASH_STATUS_OK,
-        .flags = 0,
-        },
-#ifndef CSS15
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_FLASH_STATUS_REGISTER,
-        .type = V4L2_CTRL_TYPE_BOOLEAN,
-        .name = "Flash Status Register",
-        .min = 0,
-        .max = 100,
-        .step = 1,
-        .def = 0,
-        .flags = 0,
-        },
-#endif
-};
-
-/* -----------------------------------------------------------------------------
- * V4L2 subdev core operations
- */
-
-/* Put device into known state. */
-static int lm3554_setup(struct lm3554 *flash)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(&flash->sd);
-       int ret;
-
-       /* clear the flags register */
-       ret = lm3554_read(flash, LM3554_FLAGS_REG);
-       if (ret < 0)
-               return ret;
-
-       dev_dbg(&client->dev, "Fault info: %02x\n", ret);
-
-       ret = lm3554_set_config1(flash);
-       if (ret < 0)
-               return ret;
-
-       ret = lm3554_set_duration(flash);
-       if (ret < 0)
-               return ret;
-
-       ret = lm3554_set_torch(flash);
-       if (ret < 0)
-               return ret;
-
-       ret = lm3554_set_flash(flash);
-       if (ret < 0)
-               return ret;
-
-       /* read status */
-       ret = lm3554_read_status(flash);
-       if (ret < 0)
-               return ret;
-
-       return ret ? -EIO : 0;
-}
-
-static int __lm3554_s_power(struct lm3554 *flash, int power)
-{
-       struct lm3554_platform_data *pdata = flash->pdata;
-       int ret;
-
-       /*initialize flash driver*/
-       gpio_set_value(pdata->gpio_reset, power);
-       usleep_range(100, 100 + 1);
-
-       if (power) {
-               /* Setup default values. This makes sure that the chip
-                * is in a known state.
-                */
-               ret = lm3554_setup(flash);
-               if (ret < 0) {
-                       __lm3554_s_power(flash, 0);
-                       return ret;
-               }
-       }
-
-       return 0;
-}
-
-static int lm3554_s_power(struct v4l2_subdev *sd, int power)
-{
-       struct lm3554 *flash = to_lm3554(sd);
-       int ret = 0;
-
-       mutex_lock(&flash->power_lock);
-
-       if (flash->power_count == !power) {
-               ret = __lm3554_s_power(flash, !!power);
-               if (ret < 0)
-                       goto done;
-       }
-
-       flash->power_count += power ? 1 : -1;
-       WARN_ON(flash->power_count < 0);
-
-done:
-       mutex_unlock(&flash->power_lock);
-       return ret;
-}
-
-static const struct v4l2_subdev_core_ops lm3554_core_ops = {
-       .s_power = lm3554_s_power,
-};
-
-static const struct v4l2_subdev_ops lm3554_ops = {
-       .core = &lm3554_core_ops,
-};
-
-static int lm3554_detect(struct v4l2_subdev *sd)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct i2c_adapter *adapter = client->adapter;
-       struct lm3554 *flash = to_lm3554(sd);
-       int ret;
-
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
-               dev_err(&client->dev, "lm3554_detect i2c error\n");
-               return -ENODEV;
-       }
-
-       /* Power up the flash driver and reset it */
-       ret = lm3554_s_power(&flash->sd, 1);
-       if (ret < 0) {
-               dev_err(&client->dev, "Failed to power on lm3554 LED flash\n");
-       } else {
-               dev_dbg(&client->dev, "Successfully detected lm3554 LED flash\n");
-               lm3554_s_power(&flash->sd, 0);
-       }
-
-       return ret;
-}
-
-static int lm3554_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
-{
-       return lm3554_s_power(sd, 1);
-}
-
-static int lm3554_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
-{
-       return lm3554_s_power(sd, 0);
-}
-
-static const struct v4l2_subdev_internal_ops lm3554_internal_ops = {
-       .registered = lm3554_detect,
-       .open = lm3554_open,
-       .close = lm3554_close,
-};
-
-/* -----------------------------------------------------------------------------
- *  I2C driver
- */
-#ifdef CONFIG_PM
-
-static int lm3554_suspend(struct device *dev)
-{
-       struct i2c_client *client = to_i2c_client(dev);
-       struct v4l2_subdev *subdev = i2c_get_clientdata(client);
-       struct lm3554 *flash = to_lm3554(subdev);
-       int rval;
-
-       if (flash->power_count == 0)
-               return 0;
-
-       rval = __lm3554_s_power(flash, 0);
-
-       dev_dbg(&client->dev, "Suspend %s\n", rval < 0 ? "failed" : "ok");
-
-       return rval;
-}
-
-static int lm3554_resume(struct device *dev)
-{
-       struct i2c_client *client = to_i2c_client(dev);
-       struct v4l2_subdev *subdev = i2c_get_clientdata(client);
-       struct lm3554 *flash = to_lm3554(subdev);
-       int rval;
-
-       if (flash->power_count == 0)
-               return 0;
-
-       rval = __lm3554_s_power(flash, 1);
-
-       dev_dbg(&client->dev, "Resume %s\n", rval < 0 ? "fail" : "ok");
-
-       return rval;
-}
-
-#else
-
-#define lm3554_suspend NULL
-#define lm3554_resume  NULL
-
-#endif /* CONFIG_PM */
-
-static int lm3554_gpio_init(struct i2c_client *client)
-{
-       struct v4l2_subdev *sd = i2c_get_clientdata(client);
-       struct lm3554 *flash = to_lm3554(sd);
-       struct lm3554_platform_data *pdata = flash->pdata;
-       int ret;
-
-       if (!gpio_is_valid(pdata->gpio_reset))
-               return -EINVAL;
-
-       ret = gpio_direction_output(pdata->gpio_reset, 0);
-       if (ret < 0)
-               goto err_gpio_reset;
-       dev_info(&client->dev, "flash led reset successfully\n");
-
-       if (!gpio_is_valid(pdata->gpio_strobe)) {
-               ret = -EINVAL;
-               goto err_gpio_dir_reset;
-       }
-
-       ret = gpio_direction_output(pdata->gpio_strobe, 0);
-       if (ret < 0)
-               goto err_gpio_strobe;
-
-       return 0;
-
-err_gpio_strobe:
-       gpio_free(pdata->gpio_strobe);
-err_gpio_dir_reset:
-       gpio_direction_output(pdata->gpio_reset, 0);
-err_gpio_reset:
-       gpio_free(pdata->gpio_reset);
-
-       return ret;
-}
-
-static int lm3554_gpio_uninit(struct i2c_client *client)
-{
-       struct v4l2_subdev *sd = i2c_get_clientdata(client);
-       struct lm3554 *flash = to_lm3554(sd);
-       struct lm3554_platform_data *pdata = flash->pdata;
-       int ret;
-
-       ret = gpio_direction_output(pdata->gpio_strobe, 0);
-       if (ret < 0)
-               return ret;
-
-       ret = gpio_direction_output(pdata->gpio_reset, 0);
-       if (ret < 0)
-               return ret;
-
-       gpio_free(pdata->gpio_strobe);
-       gpio_free(pdata->gpio_reset);
-       return 0;
-}
-
-static void *lm3554_platform_data_func(struct i2c_client *client)
-{
-       static struct lm3554_platform_data platform_data;
-
-       if (ACPI_COMPANION(&client->dev)) {
-               platform_data.gpio_reset =
-                   desc_to_gpio(gpiod_get_index(&(client->dev),
-                                                NULL, 2, GPIOD_OUT_LOW));
-               platform_data.gpio_strobe =
-                   desc_to_gpio(gpiod_get_index(&(client->dev),
-                                                NULL, 0, GPIOD_OUT_LOW));
-               platform_data.gpio_torch =
-                   desc_to_gpio(gpiod_get_index(&(client->dev),
-                                                NULL, 1, GPIOD_OUT_LOW));
-       } else {
-               platform_data.gpio_reset = -1;
-               platform_data.gpio_strobe = -1;
-               platform_data.gpio_torch = -1;
-       }
-
-       dev_info(&client->dev, "camera pdata: lm3554: reset: %d strobe %d torch %d\n",
-               platform_data.gpio_reset, platform_data.gpio_strobe,
-               platform_data.gpio_torch);
-
-       /* Set to TX2 mode, then ENVM/TX2 pin is a power amplifier sync input:
-        * ENVM/TX pin asserted, flash forced into torch;
-        * ENVM/TX pin desserted, flash set back;
-        */
-       platform_data.envm_tx2 = 1;
-       platform_data.tx2_polarity = 0;
-
-       /* set peak current limit to be 1000mA */
-       platform_data.current_limit = 0;
-
-       return &platform_data;
-}
-
-static int lm3554_probe(struct i2c_client *client,
-                                 const struct i2c_device_id *id)
-{
-       int err = 0;
-       struct lm3554 *flash;
-       unsigned int i;
-       int ret;
-
-       flash = kzalloc(sizeof(*flash), GFP_KERNEL);
-       if (!flash) {
-               dev_err(&client->dev, "out of memory\n");
-               return -ENOMEM;
-       }
-
-       flash->pdata = client->dev.platform_data;
-
-       if (!flash->pdata || ACPI_COMPANION(&client->dev))
-               flash->pdata = lm3554_platform_data_func(client);
-
-       v4l2_i2c_subdev_init(&flash->sd, client, &lm3554_ops);
-       flash->sd.internal_ops = &lm3554_internal_ops;
-       flash->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-       flash->mode = ATOMISP_FLASH_MODE_OFF;
-       flash->timeout = LM3554_MAX_TIMEOUT / LM3554_TIMEOUT_STEPSIZE - 1;
-       ret =
-           v4l2_ctrl_handler_init(&flash->ctrl_handler,
-                                  ARRAY_SIZE(lm3554_controls));
-       if (ret) {
-               dev_err(&client->dev, "error initialize a ctrl_handler.\n");
-               goto fail2;
-       }
-
-       for (i = 0; i < ARRAY_SIZE(lm3554_controls); i++)
-               v4l2_ctrl_new_custom(&flash->ctrl_handler, &lm3554_controls[i],
-                                    NULL);
-
-       if (flash->ctrl_handler.error) {
-
-               dev_err(&client->dev, "ctrl_handler error.\n");
-               goto fail2;
-       }
-
-       flash->sd.ctrl_handler = &flash->ctrl_handler;
-       err = media_entity_pads_init(&flash->sd.entity, 0, NULL);
-       if (err) {
-               dev_err(&client->dev, "error initialize a media entity.\n");
-               goto fail1;
-       }
-
-       flash->sd.entity.function = MEDIA_ENT_F_FLASH;
-
-       mutex_init(&flash->power_lock);
-
-       setup_timer(&flash->flash_off_delay, lm3554_flash_off_delay,
-                   (unsigned long)client);
-
-       err = lm3554_gpio_init(client);
-       if (err) {
-               dev_err(&client->dev, "gpio request/direction_output fail");
-               goto fail2;
-       }
-       if (ACPI_HANDLE(&client->dev))
-               err = atomisp_register_i2c_module(&flash->sd, NULL, LED_FLASH);
-       return 0;
-fail2:
-       media_entity_cleanup(&flash->sd.entity);
-       v4l2_ctrl_handler_free(&flash->ctrl_handler);
-fail1:
-       v4l2_device_unregister_subdev(&flash->sd);
-       kfree(flash);
-
-       return err;
-}
-
-static int lm3554_remove(struct i2c_client *client)
-{
-       struct v4l2_subdev *sd = i2c_get_clientdata(client);
-       struct lm3554 *flash = to_lm3554(sd);
-       int ret;
-
-       media_entity_cleanup(&flash->sd.entity);
-       v4l2_ctrl_handler_free(&flash->ctrl_handler);
-       v4l2_device_unregister_subdev(sd);
-
-       atomisp_gmin_remove_subdev(sd);
-
-       del_timer_sync(&flash->flash_off_delay);
-
-       ret = lm3554_gpio_uninit(client);
-       if (ret < 0)
-               goto fail;
-
-       kfree(flash);
-
-       return 0;
-fail:
-       dev_err(&client->dev, "gpio request/direction_output fail");
-       return ret;
-}
-
-static const struct i2c_device_id lm3554_id[] = {
-       {LM3554_NAME, 0},
-       {},
-};
-
-MODULE_DEVICE_TABLE(i2c, lm3554_id);
-
-static const struct dev_pm_ops lm3554_pm_ops = {
-       .suspend = lm3554_suspend,
-       .resume = lm3554_resume,
-};
-
-static const struct acpi_device_id lm3554_acpi_match[] = {
-       { "INTCF1C" },
-       {},
-};
-
-MODULE_DEVICE_TABLE(acpi, lm3554_acpi_match);
-
-static struct i2c_driver lm3554_driver = {
-       .driver = {
-               .name = LM3554_NAME,
-               .pm   = &lm3554_pm_ops,
-               .acpi_match_table = ACPI_PTR(lm3554_acpi_match),
-       },
-       .probe = lm3554_probe,
-       .remove = lm3554_remove,
-       .id_table = lm3554_id,
-};
-
-static __init int init_lm3554(void)
-{
-       return i2c_add_driver(&lm3554_driver);
-}
-
-static __exit void exit_lm3554(void)
-{
-       i2c_del_driver(&lm3554_driver);
-}
-
-module_init(init_lm3554);
-module_exit(exit_lm3554);
-MODULE_AUTHOR("Jing Tao <jing.tao@intel.com>");
-MODULE_DESCRIPTION("LED flash driver for LM3554");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/media/atomisp/i2c/mt9m114.c b/drivers/staging/media/atomisp/i2c/mt9m114.c
deleted file mode 100644 (file)
index 3c837cb..0000000
+++ /dev/null
@@ -1,1963 +0,0 @@
-/*
- * Support for mt9m114 Camera Sensor.
- *
- * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/kmod.h>
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/gpio.h>
-#include <linux/acpi.h>
-#include "../include/linux/atomisp_gmin_platform.h"
-#include <media/v4l2-device.h>
-
-#include "mt9m114.h"
-
-#define to_mt9m114_sensor(sd) container_of(sd, struct mt9m114_device, sd)
-
-/*
- * TODO: use debug parameter to actually define when debug messages should
- * be printed.
- */
-static int debug;
-static int aaalock;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Debug level (0-1)");
-
-static int mt9m114_t_vflip(struct v4l2_subdev *sd, int value);
-static int mt9m114_t_hflip(struct v4l2_subdev *sd, int value);
-static int mt9m114_wait_state(struct i2c_client *client, int timeout);
-
-static int
-mt9m114_read_reg(struct i2c_client *client, u16 data_length, u32 reg, u32 *val)
-{
-       int err;
-       struct i2c_msg msg[2];
-       unsigned char data[4];
-
-       if (!client->adapter) {
-               v4l2_err(client, "%s error, no client->adapter\n", __func__);
-               return -ENODEV;
-       }
-
-       if (data_length != MISENSOR_8BIT && data_length != MISENSOR_16BIT
-                                        && data_length != MISENSOR_32BIT) {
-               v4l2_err(client, "%s error, invalid data length\n", __func__);
-               return -EINVAL;
-       }
-
-       msg[0].addr = client->addr;
-       msg[0].flags = 0;
-       msg[0].len = MSG_LEN_OFFSET;
-       msg[0].buf = data;
-
-       /* high byte goes out first */
-       data[0] = (u16) (reg >> 8);
-       data[1] = (u16) (reg & 0xff);
-
-       msg[1].addr = client->addr;
-       msg[1].len = data_length;
-       msg[1].flags = I2C_M_RD;
-       msg[1].buf = data;
-
-       err = i2c_transfer(client->adapter, msg, 2);
-
-       if (err >= 0) {
-               *val = 0;
-               /* high byte comes first */
-               if (data_length == MISENSOR_8BIT)
-                       *val = data[0];
-               else if (data_length == MISENSOR_16BIT)
-                       *val = data[1] + (data[0] << 8);
-               else
-                       *val = data[3] + (data[2] << 8) +
-                           (data[1] << 16) + (data[0] << 24);
-
-               return 0;
-       }
-
-       dev_err(&client->dev, "read from offset 0x%x error %d", reg, err);
-       return err;
-}
-
-static int
-mt9m114_write_reg(struct i2c_client *client, u16 data_length, u16 reg, u32 val)
-{
-       int num_msg;
-       struct i2c_msg msg;
-       unsigned char data[6] = {0};
-       u16 *wreg;
-       int retry = 0;
-
-       if (!client->adapter) {
-               v4l2_err(client, "%s error, no client->adapter\n", __func__);
-               return -ENODEV;
-       }
-
-       if (data_length != MISENSOR_8BIT && data_length != MISENSOR_16BIT
-                                        && data_length != MISENSOR_32BIT) {
-               v4l2_err(client, "%s error, invalid data_length\n", __func__);
-               return -EINVAL;
-       }
-
-       memset(&msg, 0, sizeof(msg));
-
-again:
-       msg.addr = client->addr;
-       msg.flags = 0;
-       msg.len = 2 + data_length;
-       msg.buf = data;
-
-       /* high byte goes out first */
-       wreg = (u16 *)data;
-       *wreg = cpu_to_be16(reg);
-
-       if (data_length == MISENSOR_8BIT) {
-               data[2] = (u8)(val);
-       } else if (data_length == MISENSOR_16BIT) {
-               u16 *wdata = (u16 *)&data[2];
-               *wdata = be16_to_cpu((u16)val);
-       } else {
-               /* MISENSOR_32BIT */
-               u32 *wdata = (u32 *)&data[2];
-               *wdata = be32_to_cpu(val);
-       }
-
-       num_msg = i2c_transfer(client->adapter, &msg, 1);
-
-       /*
-        * HACK: Need some delay here for Rev 2 sensors otherwise some
-        * registers do not seem to load correctly.
-        */
-       mdelay(1);
-
-       if (num_msg >= 0)
-               return 0;
-
-       dev_err(&client->dev, "write error: wrote 0x%x to offset 0x%x error %d",
-               val, reg, num_msg);
-       if (retry <= I2C_RETRY_COUNT) {
-               dev_dbg(&client->dev, "retrying... %d", retry);
-               retry++;
-               msleep(20);
-               goto again;
-       }
-
-       return num_msg;
-}
-
-/**
- * misensor_rmw_reg - Read/Modify/Write a value to a register in the sensor
- * device
- * @client: i2c driver client structure
- * @data_length: 8/16/32-bits length
- * @reg: register address
- * @mask: masked out bits
- * @set: bits set
- *
- * Read/modify/write a value to a register in the  sensor device.
- * Returns zero if successful, or non-zero otherwise.
- */
-static int
-misensor_rmw_reg(struct i2c_client *client, u16 data_length, u16 reg,
-                    u32 mask, u32 set)
-{
-       int err;
-       u32 val;
-
-       /* Exit when no mask */
-       if (mask == 0)
-               return 0;
-
-       /* @mask must not exceed data length */
-       switch (data_length) {
-       case MISENSOR_8BIT:
-               if (mask & ~0xff)
-                       return -EINVAL;
-               break;
-       case MISENSOR_16BIT:
-               if (mask & ~0xffff)
-                       return -EINVAL;
-               break;
-       case MISENSOR_32BIT:
-               break;
-       default:
-               /* Wrong @data_length */
-               return -EINVAL;
-       }
-
-       err = mt9m114_read_reg(client, data_length, reg, &val);
-       if (err) {
-               v4l2_err(client, "misensor_rmw_reg error exit, read failed\n");
-               return -EINVAL;
-       }
-
-       val &= ~mask;
-
-       /*
-        * Perform the OR function if the @set exists.
-        * Shift @set value to target bit location. @set should set only
-        * bits included in @mask.
-        *
-        * REVISIT: This function expects @set to be non-shifted. Its shift
-        * value is then defined to be equal to mask's LSB position.
-        * How about to inform values in their right offset position and avoid
-        * this unneeded shift operation?
-        */
-       set <<= ffs(mask) - 1;
-       val |= set & mask;
-
-       err = mt9m114_write_reg(client, data_length, reg, val);
-       if (err) {
-               v4l2_err(client, "misensor_rmw_reg error exit, write failed\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-
-static int __mt9m114_flush_reg_array(struct i2c_client *client,
-                                    struct mt9m114_write_ctrl *ctrl)
-{
-       struct i2c_msg msg;
-       const int num_msg = 1;
-       int ret;
-       int retry = 0;
-
-       if (ctrl->index == 0)
-               return 0;
-
-again:
-       msg.addr = client->addr;
-       msg.flags = 0;
-       msg.len = 2 + ctrl->index;
-       ctrl->buffer.addr = cpu_to_be16(ctrl->buffer.addr);
-       msg.buf = (u8 *)&ctrl->buffer;
-
-       ret = i2c_transfer(client->adapter, &msg, num_msg);
-       if (ret != num_msg) {
-               if (++retry <= I2C_RETRY_COUNT) {
-                       dev_dbg(&client->dev, "retrying... %d\n", retry);
-                       msleep(20);
-                       goto again;
-               }
-               dev_err(&client->dev, "%s: i2c transfer error\n", __func__);
-               return -EIO;
-       }
-
-       ctrl->index = 0;
-
-       /*
-        * REVISIT: Previously we had a delay after writing data to sensor.
-        * But it was removed as our tests have shown it is not necessary
-        * anymore.
-        */
-
-       return 0;
-}
-
-static int __mt9m114_buf_reg_array(struct i2c_client *client,
-                                  struct mt9m114_write_ctrl *ctrl,
-                                  const struct misensor_reg *next)
-{
-       u16 *data16;
-       u32 *data32;
-       int err;
-
-       /* Insufficient buffer? Let's flush and get more free space. */
-       if (ctrl->index + next->length >= MT9M114_MAX_WRITE_BUF_SIZE) {
-               err = __mt9m114_flush_reg_array(client, ctrl);
-               if (err)
-                       return err;
-       }
-
-       switch (next->length) {
-       case MISENSOR_8BIT:
-               ctrl->buffer.data[ctrl->index] = (u8)next->val;
-               break;
-       case MISENSOR_16BIT:
-               data16 = (u16 *)&ctrl->buffer.data[ctrl->index];
-               *data16 = cpu_to_be16((u16)next->val);
-               break;
-       case MISENSOR_32BIT:
-               data32 = (u32 *)&ctrl->buffer.data[ctrl->index];
-               *data32 = cpu_to_be32(next->val);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       /* When first item is added, we need to store its starting address */
-       if (ctrl->index == 0)
-               ctrl->buffer.addr = next->reg;
-
-       ctrl->index += next->length;
-
-       return 0;
-}
-
-static int
-__mt9m114_write_reg_is_consecutive(struct i2c_client *client,
-                                  struct mt9m114_write_ctrl *ctrl,
-                                  const struct misensor_reg *next)
-{
-       if (ctrl->index == 0)
-               return 1;
-
-       return ctrl->buffer.addr + ctrl->index == next->reg;
-}
-
-/*
- * mt9m114_write_reg_array - Initializes a list of mt9m114 registers
- * @client: i2c driver client structure
- * @reglist: list of registers to be written
- * @poll: completion polling requirement
- * This function initializes a list of registers. When consecutive addresses
- * are found in a row on the list, this function creates a buffer and sends
- * consecutive data in a single i2c_transfer().
- *
- * __mt9m114_flush_reg_array, __mt9m114_buf_reg_array() and
- * __mt9m114_write_reg_is_consecutive() are internal functions to
- * mt9m114_write_reg_array() and should be not used anywhere else.
- *
- */
-static int mt9m114_write_reg_array(struct i2c_client *client,
-                               const struct misensor_reg *reglist,
-                               int poll)
-{
-       const struct misensor_reg *next = reglist;
-       struct mt9m114_write_ctrl ctrl;
-       int err;
-
-       if (poll == PRE_POLLING) {
-               err = mt9m114_wait_state(client, MT9M114_WAIT_STAT_TIMEOUT);
-               if (err)
-                       return err;
-       }
-
-       ctrl.index = 0;
-       for (; next->length != MISENSOR_TOK_TERM; next++) {
-               switch (next->length & MISENSOR_TOK_MASK) {
-               case MISENSOR_TOK_DELAY:
-                       err = __mt9m114_flush_reg_array(client, &ctrl);
-                       if (err)
-                               return err;
-                       msleep(next->val);
-                       break;
-               case MISENSOR_TOK_RMW:
-                       err = __mt9m114_flush_reg_array(client, &ctrl);
-                       err |= misensor_rmw_reg(client,
-                                               next->length &
-                                                       ~MISENSOR_TOK_RMW,
-                                               next->reg, next->val,
-                                               next->val2);
-                       if (err) {
-                               dev_err(&client->dev, "%s read err. aborted\n",
-                                       __func__);
-                               return -EINVAL;
-                       }
-                       break;
-               default:
-                       /*
-                        * If next address is not consecutive, data needs to be
-                        * flushed before proceed.
-                        */
-                       if (!__mt9m114_write_reg_is_consecutive(client, &ctrl,
-                                                               next)) {
-                               err = __mt9m114_flush_reg_array(client, &ctrl);
-                               if (err)
-                                       return err;
-                       }
-                       err = __mt9m114_buf_reg_array(client, &ctrl, next);
-                       if (err) {
-                               v4l2_err(client, "%s: write error, aborted\n",
-                                        __func__);
-                               return err;
-                       }
-                       break;
-               }
-       }
-
-       err = __mt9m114_flush_reg_array(client, &ctrl);
-       if (err)
-               return err;
-
-       if (poll == POST_POLLING)
-               return mt9m114_wait_state(client, MT9M114_WAIT_STAT_TIMEOUT);
-
-       return 0;
-}
-
-static int mt9m114_wait_state(struct i2c_client *client, int timeout)
-{
-       int ret;
-       unsigned int val;
-
-       while (timeout-- > 0) {
-               ret = mt9m114_read_reg(client, MISENSOR_16BIT, 0x0080, &val);
-               if (ret)
-                       return ret;
-               if ((val & 0x2) == 0)
-                       return 0;
-               msleep(20);
-       }
-
-       return -EINVAL;
-
-}
-
-static int mt9m114_set_suspend(struct v4l2_subdev *sd)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       return mt9m114_write_reg_array(client,
-                       mt9m114_standby_reg, POST_POLLING);
-}
-
-static int mt9m114_init_common(struct v4l2_subdev *sd)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       return mt9m114_write_reg_array(client, mt9m114_common, PRE_POLLING);
-}
-
-static int power_ctrl(struct v4l2_subdev *sd, bool flag)
-{
-       int ret;
-       struct mt9m114_device *dev = to_mt9m114_sensor(sd);
-
-       if (!dev || !dev->platform_data)
-               return -ENODEV;
-
-       /* Non-gmin platforms use the legacy callback */
-       if (dev->platform_data->power_ctrl)
-               return dev->platform_data->power_ctrl(sd, flag);
-
-       if (flag) {
-               ret = dev->platform_data->v2p8_ctrl(sd, 1);
-               if (ret == 0) {
-                       ret = dev->platform_data->v1p8_ctrl(sd, 1);
-                       if (ret)
-                               ret = dev->platform_data->v2p8_ctrl(sd, 0);
-               }
-       } else {
-               ret = dev->platform_data->v2p8_ctrl(sd, 0);
-               ret = dev->platform_data->v1p8_ctrl(sd, 0);
-       }
-       return ret;
-}
-
-static int gpio_ctrl(struct v4l2_subdev *sd, bool flag)
-{
-       int ret;
-       struct mt9m114_device *dev = to_mt9m114_sensor(sd);
-
-       if (!dev || !dev->platform_data)
-               return -ENODEV;
-
-       /* Non-gmin platforms use the legacy callback */
-       if (dev->platform_data->gpio_ctrl)
-               return dev->platform_data->gpio_ctrl(sd, flag);
-
-       /* Note: current modules wire only one GPIO signal (RESET#),
-        * but the schematic wires up two to the connector.  BIOS
-        * versions have been unfortunately inconsistent with which
-        * ACPI index RESET# is on, so hit both */
-
-       if (flag) {
-               ret = dev->platform_data->gpio0_ctrl(sd, 0);
-               ret = dev->platform_data->gpio1_ctrl(sd, 0);
-               msleep(60);
-               ret |= dev->platform_data->gpio0_ctrl(sd, 1);
-               ret |= dev->platform_data->gpio1_ctrl(sd, 1);
-       } else {
-               ret = dev->platform_data->gpio0_ctrl(sd, 0);
-               ret = dev->platform_data->gpio1_ctrl(sd, 0);
-       }
-       return ret;
-}
-
-static int power_up(struct v4l2_subdev *sd)
-{
-       struct mt9m114_device *dev = to_mt9m114_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret;
-
-       if (NULL == dev->platform_data) {
-               dev_err(&client->dev, "no camera_sensor_platform_data");
-               return -ENODEV;
-       }
-
-       /* power control */
-       ret = power_ctrl(sd, 1);
-       if (ret)
-               goto fail_power;
-
-       /* flis clock control */
-       ret = dev->platform_data->flisclk_ctrl(sd, 1);
-       if (ret)
-               goto fail_clk;
-
-       /* gpio ctrl */
-       ret = gpio_ctrl(sd, 1);
-       if (ret)
-               dev_err(&client->dev, "gpio failed 1\n");
-       /*
-        * according to DS, 44ms is needed between power up and first i2c
-        * commend
-        */
-       msleep(50);
-
-       return 0;
-
-fail_clk:
-       dev->platform_data->flisclk_ctrl(sd, 0);
-fail_power:
-       power_ctrl(sd, 0);
-       dev_err(&client->dev, "sensor power-up failed\n");
-
-       return ret;
-}
-
-static int power_down(struct v4l2_subdev *sd)
-{
-       struct mt9m114_device *dev = to_mt9m114_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret;
-
-       if (NULL == dev->platform_data) {
-               dev_err(&client->dev, "no camera_sensor_platform_data");
-               return -ENODEV;
-       }
-
-       ret = dev->platform_data->flisclk_ctrl(sd, 0);
-       if (ret)
-               dev_err(&client->dev, "flisclk failed\n");
-
-       /* gpio ctrl */
-       ret = gpio_ctrl(sd, 0);
-       if (ret)
-               dev_err(&client->dev, "gpio failed 1\n");
-
-       /* power control */
-       ret = power_ctrl(sd, 0);
-       if (ret)
-               dev_err(&client->dev, "vprog failed.\n");
-
-       /*according to DS, 20ms is needed after power down*/
-       msleep(20);
-
-       return ret;
-}
-
-static int mt9m114_s_power(struct v4l2_subdev *sd, int power)
-{
-       if (power == 0)
-               return power_down(sd);
-       else {
-               if (power_up(sd))
-                       return -EINVAL;
-
-               return mt9m114_init_common(sd);
-       }
-}
-
-/*
- * distance - calculate the distance
- * @res: resolution
- * @w: width
- * @h: height
- *
- * Get the gap between resolution and w/h.
- * res->width/height smaller than w/h wouldn't be considered.
- * Returns the value of gap or -1 if fail.
- */
-#define LARGEST_ALLOWED_RATIO_MISMATCH 600
-static int distance(struct mt9m114_res_struct const *res, u32 w, u32 h)
-{
-       unsigned int w_ratio;
-       unsigned int h_ratio;
-       int match;
-
-       if (w == 0)
-               return -1;
-       w_ratio = (res->width << 13) / w;
-       if (h == 0)
-               return -1;
-       h_ratio = (res->height << 13) / h;
-       if (h_ratio == 0)
-               return -1;
-       match   = abs(((w_ratio << 13) / h_ratio) - 8192);
-
-       if ((w_ratio < 8192) || (h_ratio < 8192) ||
-           (match > LARGEST_ALLOWED_RATIO_MISMATCH))
-               return -1;
-
-       return w_ratio + h_ratio;
-}
-
-/* Return the nearest higher resolution index */
-static int nearest_resolution_index(int w, int h)
-{
-       int i;
-       int idx = -1;
-       int dist;
-       int min_dist = INT_MAX;
-       const struct mt9m114_res_struct *tmp_res = NULL;
-
-       for (i = 0; i < ARRAY_SIZE(mt9m114_res); i++) {
-               tmp_res = &mt9m114_res[i];
-               dist = distance(tmp_res, w, h);
-               if (dist == -1)
-                       continue;
-               if (dist < min_dist) {
-                       min_dist = dist;
-                       idx = i;
-               }
-       }
-
-       return idx;
-}
-
-static int mt9m114_try_res(u32 *w, u32 *h)
-{
-       int idx = 0;
-
-       if ((*w > MT9M114_RES_960P_SIZE_H)
-               || (*h > MT9M114_RES_960P_SIZE_V)) {
-               *w = MT9M114_RES_960P_SIZE_H;
-               *h = MT9M114_RES_960P_SIZE_V;
-       } else {
-               idx = nearest_resolution_index(*w, *h);
-
-               /*
-                * nearest_resolution_index() doesn't return smaller
-                *  resolutions. If it fails, it means the requested
-                *  resolution is higher than wecan support. Fallback
-                *  to highest possible resolution in this case.
-                */
-               if (idx == -1)
-                       idx = ARRAY_SIZE(mt9m114_res) - 1;
-
-               *w = mt9m114_res[idx].width;
-               *h = mt9m114_res[idx].height;
-       }
-
-       return 0;
-}
-
-static struct mt9m114_res_struct *mt9m114_to_res(u32 w, u32 h)
-{
-       int  index;
-
-       for (index = 0; index < N_RES; index++) {
-               if ((mt9m114_res[index].width == w) &&
-                   (mt9m114_res[index].height == h))
-                       break;
-       }
-
-       /* No mode found */
-       if (index >= N_RES)
-               return NULL;
-
-       return &mt9m114_res[index];
-}
-
-static int mt9m114_res2size(struct v4l2_subdev *sd, int *h_size, int *v_size)
-{
-       struct mt9m114_device *dev = to_mt9m114_sensor(sd);
-       unsigned short hsize;
-       unsigned short vsize;
-
-       switch (dev->res) {
-       case MT9M114_RES_736P:
-               hsize = MT9M114_RES_736P_SIZE_H;
-               vsize = MT9M114_RES_736P_SIZE_V;
-               break;
-       case MT9M114_RES_864P:
-               hsize = MT9M114_RES_864P_SIZE_H;
-               vsize = MT9M114_RES_864P_SIZE_V;
-               break;
-       case MT9M114_RES_960P:
-               hsize = MT9M114_RES_960P_SIZE_H;
-               vsize = MT9M114_RES_960P_SIZE_V;
-               break;
-       default:
-               v4l2_err(sd, "%s: Resolution 0x%08x unknown\n", __func__,
-                        dev->res);
-               return -EINVAL;
-       }
-
-       if (h_size != NULL)
-               *h_size = hsize;
-       if (v_size != NULL)
-               *v_size = vsize;
-
-       return 0;
-}
-
-static int mt9m114_get_intg_factor(struct i2c_client *client,
-                               struct camera_mipi_info *info,
-                               const struct mt9m114_res_struct *res)
-{
-       struct atomisp_sensor_mode_data *buf = &info->data;
-       u32 reg_val;
-       int ret;
-
-       if (info == NULL)
-               return -EINVAL;
-
-       ret =  mt9m114_read_reg(client, MISENSOR_32BIT,
-                                       REG_PIXEL_CLK, &reg_val);
-       if (ret)
-               return ret;
-       buf->vt_pix_clk_freq_mhz = reg_val;
-
-       /* get integration time */
-       buf->coarse_integration_time_min = MT9M114_COARSE_INTG_TIME_MIN;
-       buf->coarse_integration_time_max_margin =
-                                       MT9M114_COARSE_INTG_TIME_MAX_MARGIN;
-
-       buf->fine_integration_time_min = MT9M114_FINE_INTG_TIME_MIN;
-       buf->fine_integration_time_max_margin =
-                                       MT9M114_FINE_INTG_TIME_MAX_MARGIN;
-
-       buf->fine_integration_time_def = MT9M114_FINE_INTG_TIME_MIN;
-
-       buf->frame_length_lines = res->lines_per_frame;
-       buf->line_length_pck = res->pixels_per_line;
-       buf->read_mode = res->bin_mode;
-
-       /* get the cropping and output resolution to ISP for this mode. */
-       ret =  mt9m114_read_reg(client, MISENSOR_16BIT,
-                                       REG_H_START, &reg_val);
-       if (ret)
-               return ret;
-       buf->crop_horizontal_start = reg_val;
-
-       ret =  mt9m114_read_reg(client, MISENSOR_16BIT,
-                                       REG_V_START, &reg_val);
-       if (ret)
-               return ret;
-       buf->crop_vertical_start = reg_val;
-
-       ret = mt9m114_read_reg(client, MISENSOR_16BIT,
-                                       REG_H_END, &reg_val);
-       if (ret)
-               return ret;
-       buf->crop_horizontal_end = reg_val;
-
-       ret = mt9m114_read_reg(client, MISENSOR_16BIT,
-                                       REG_V_END, &reg_val);
-       if (ret)
-               return ret;
-       buf->crop_vertical_end = reg_val;
-
-       ret = mt9m114_read_reg(client, MISENSOR_16BIT,
-                                       REG_WIDTH, &reg_val);
-       if (ret)
-               return ret;
-       buf->output_width = reg_val;
-
-       ret = mt9m114_read_reg(client, MISENSOR_16BIT,
-                                       REG_HEIGHT, &reg_val);
-       if (ret)
-               return ret;
-       buf->output_height = reg_val;
-
-       ret = mt9m114_read_reg(client, MISENSOR_16BIT,
-                                       REG_TIMING_HTS, &reg_val);
-       if (ret)
-               return ret;
-       buf->line_length_pck = reg_val;
-
-       ret = mt9m114_read_reg(client, MISENSOR_16BIT,
-                                       REG_TIMING_VTS, &reg_val);
-       if (ret)
-               return ret;
-       buf->frame_length_lines = reg_val;
-
-       buf->binning_factor_x = res->bin_factor_x ?
-                                       res->bin_factor_x : 1;
-       buf->binning_factor_y = res->bin_factor_y ?
-                                       res->bin_factor_y : 1;
-       return 0;
-}
-
-static int mt9m114_get_fmt(struct v4l2_subdev *sd,
-                               struct v4l2_subdev_pad_config *cfg,
-                               struct v4l2_subdev_format *format)
-{
-       struct v4l2_mbus_framefmt *fmt = &format->format;
-       int width, height;
-       int ret;
-       if (format->pad)
-               return -EINVAL;
-       fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
-
-       ret = mt9m114_res2size(sd, &width, &height);
-       if (ret)
-               return ret;
-       fmt->width = width;
-       fmt->height = height;
-
-       return 0;
-}
-
-static int mt9m114_set_fmt(struct v4l2_subdev *sd,
-                          struct v4l2_subdev_pad_config *cfg,
-                          struct v4l2_subdev_format *format)
-{
-       struct v4l2_mbus_framefmt *fmt = &format->format;
-       struct i2c_client *c = v4l2_get_subdevdata(sd);
-       struct mt9m114_device *dev = to_mt9m114_sensor(sd);
-       struct mt9m114_res_struct *res_index;
-       u32 width = fmt->width;
-       u32 height = fmt->height;
-       struct camera_mipi_info *mt9m114_info = NULL;
-
-       int ret;
-       if (format->pad)
-               return -EINVAL;
-       dev->streamon = 0;
-       dev->first_exp = MT9M114_DEFAULT_FIRST_EXP;
-
-       mt9m114_info = v4l2_get_subdev_hostdata(sd);
-       if (mt9m114_info == NULL)
-               return -EINVAL;
-
-       mt9m114_try_res(&width, &height);
-       if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
-               cfg->try_fmt = *fmt;
-               return 0;
-       }
-       res_index = mt9m114_to_res(width, height);
-
-       /* Sanity check */
-       if (unlikely(!res_index)) {
-               WARN_ON(1);
-               return -EINVAL;
-       }
-
-       switch (res_index->res) {
-       case MT9M114_RES_736P:
-               ret = mt9m114_write_reg_array(c, mt9m114_736P_init, NO_POLLING);
-               ret += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE,
-                               MISENSOR_R_MODE_MASK, MISENSOR_NORMAL_SET);
-               break;
-       case MT9M114_RES_864P:
-               ret = mt9m114_write_reg_array(c, mt9m114_864P_init, NO_POLLING);
-               ret += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE,
-                               MISENSOR_R_MODE_MASK, MISENSOR_NORMAL_SET);
-               break;
-       case MT9M114_RES_960P:
-               ret = mt9m114_write_reg_array(c, mt9m114_976P_init, NO_POLLING);
-               /* set sensor read_mode to Normal */
-               ret += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE,
-                               MISENSOR_R_MODE_MASK, MISENSOR_NORMAL_SET);
-               break;
-       default:
-               v4l2_err(sd, "set resolution: %d failed!\n", res_index->res);
-               return -EINVAL;
-       }
-
-       if (ret)
-               return -EINVAL;
-
-       ret = mt9m114_write_reg_array(c, mt9m114_chgstat_reg, POST_POLLING);
-       if (ret < 0)
-               return ret;
-
-       if (mt9m114_set_suspend(sd))
-               return -EINVAL;
-
-       if (dev->res != res_index->res) {
-               int index;
-
-               /* Switch to different size */
-               if (width <= 640) {
-                       dev->nctx = 0x00; /* Set for context A */
-               } else {
-                       /*
-                        * Context B is used for resolutions larger than 640x480
-                        * Using YUV for Context B.
-                        */
-                       dev->nctx = 0x01; /* set for context B */
-               }
-
-               /*
-                * Marked current sensor res as being "used"
-                *
-                * REVISIT: We don't need to use an "used" field on each mode
-                * list entry to know which mode is selected. If this
-                * information is really necessary, how about to use a single
-                * variable on sensor dev struct?
-                */
-               for (index = 0; index < N_RES; index++) {
-                       if ((width == mt9m114_res[index].width) &&
-                           (height == mt9m114_res[index].height)) {
-                               mt9m114_res[index].used = true;
-                               continue;
-                       }
-                       mt9m114_res[index].used = false;
-               }
-       }
-       ret = mt9m114_get_intg_factor(c, mt9m114_info,
-                                       &mt9m114_res[res_index->res]);
-       if (ret) {
-               dev_err(&c->dev, "failed to get integration_factor\n");
-               return -EINVAL;
-       }
-       /*
-        * mt9m114 - we don't poll for context switch
-        * because it does not happen with streaming disabled.
-        */
-       dev->res = res_index->res;
-
-       fmt->width = width;
-       fmt->height = height;
-       fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
-       return 0;
-}
-
-/* TODO: Update to SOC functions, remove exposure and gain */
-static int mt9m114_g_focal(struct v4l2_subdev *sd, s32 *val)
-{
-       *val = (MT9M114_FOCAL_LENGTH_NUM << 16) | MT9M114_FOCAL_LENGTH_DEM;
-       return 0;
-}
-
-static int mt9m114_g_fnumber(struct v4l2_subdev *sd, s32 *val)
-{
-       /*const f number for mt9m114*/
-       *val = (MT9M114_F_NUMBER_DEFAULT_NUM << 16) | MT9M114_F_NUMBER_DEM;
-       return 0;
-}
-
-static int mt9m114_g_fnumber_range(struct v4l2_subdev *sd, s32 *val)
-{
-       *val = (MT9M114_F_NUMBER_DEFAULT_NUM << 24) |
-               (MT9M114_F_NUMBER_DEM << 16) |
-               (MT9M114_F_NUMBER_DEFAULT_NUM << 8) | MT9M114_F_NUMBER_DEM;
-       return 0;
-}
-
-/* Horizontal flip the image. */
-static int mt9m114_g_hflip(struct v4l2_subdev *sd, s32 *val)
-{
-       struct i2c_client *c = v4l2_get_subdevdata(sd);
-       int ret;
-       u32 data;
-       ret = mt9m114_read_reg(c, MISENSOR_16BIT,
-                       (u32)MISENSOR_READ_MODE, &data);
-       if (ret)
-               return ret;
-       *val = !!(data & MISENSOR_HFLIP_MASK);
-
-       return 0;
-}
-
-static int mt9m114_g_vflip(struct v4l2_subdev *sd, s32 *val)
-{
-       struct i2c_client *c = v4l2_get_subdevdata(sd);
-       int ret;
-       u32 data;
-
-       ret = mt9m114_read_reg(c, MISENSOR_16BIT,
-                       (u32)MISENSOR_READ_MODE, &data);
-       if (ret)
-               return ret;
-       *val = !!(data & MISENSOR_VFLIP_MASK);
-
-       return 0;
-}
-
-static long mt9m114_s_exposure(struct v4l2_subdev *sd,
-                              struct atomisp_exposure *exposure)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct mt9m114_device *dev = to_mt9m114_sensor(sd);
-       int ret = 0;
-       unsigned int coarse_integration = 0;
-       unsigned int fine_integration = 0;
-       unsigned int FLines = 0;
-       unsigned int FrameLengthLines = 0; /* ExposureTime.FrameLengthLines; */
-       unsigned int AnalogGain, DigitalGain;
-       u32 AnalogGainToWrite = 0;
-       u16 exposure_local[3];
-
-       dev_dbg(&client->dev, "%s(0x%X 0x%X 0x%X)\n", __func__,
-                   exposure->integration_time[0], exposure->gain[0],
-                   exposure->gain[1]);
-
-       coarse_integration = exposure->integration_time[0];
-       /* fine_integration = ExposureTime.FineIntegrationTime; */
-       /* FrameLengthLines = ExposureTime.FrameLengthLines; */
-       FLines = mt9m114_res[dev->res].lines_per_frame;
-       AnalogGain = exposure->gain[0];
-       DigitalGain = exposure->gain[1];
-       if (!dev->streamon) {
-               /*Save the first exposure values while stream is off*/
-               dev->first_exp = coarse_integration;
-               dev->first_gain = AnalogGain;
-               dev->first_diggain = DigitalGain;
-       }
-       /* DigitalGain = 0x400 * (((u16) DigitalGain) >> 8) +
-       ((unsigned int)(0x400 * (((u16) DigitalGain) & 0xFF)) >>8); */
-
-       /* set frame length */
-       if (FLines < coarse_integration + 6)
-               FLines = coarse_integration + 6;
-       if (FLines < FrameLengthLines)
-               FLines = FrameLengthLines;
-       ret = mt9m114_write_reg(client, MISENSOR_16BIT, 0x300A, FLines);
-       if (ret) {
-               v4l2_err(client, "%s: fail to set FLines\n", __func__);
-               return -EINVAL;
-       }
-
-       /* set coarse/fine integration */
-       exposure_local[0] = REG_EXPO_COARSE;
-       exposure_local[1] = (u16)coarse_integration;
-       exposure_local[2] = (u16)fine_integration;
-       /* 3A provide real exposure time.
-               should not translate to any value here. */
-       ret = mt9m114_write_reg(client, MISENSOR_16BIT,
-                       REG_EXPO_COARSE, (u16)(coarse_integration));
-       if (ret) {
-               v4l2_err(client, "%s: fail to set exposure time\n", __func__);
-               return -EINVAL;
-       }
-
-       /*
-       // set analog/digital gain
-       switch(AnalogGain)
-       {
-       case 0:
-         AnalogGainToWrite = 0x0;
-         break;
-       case 1:
-         AnalogGainToWrite = 0x20;
-         break;
-       case 2:
-         AnalogGainToWrite = 0x60;
-         break;
-       case 4:
-         AnalogGainToWrite = 0xA0;
-         break;
-       case 8:
-         AnalogGainToWrite = 0xE0;
-         break;
-       default:
-         AnalogGainToWrite = 0x20;
-         break;
-       }
-       */
-       if (DigitalGain >= 16 || DigitalGain <= 1)
-               DigitalGain = 1;
-       /* AnalogGainToWrite =
-               (u16)((DigitalGain << 12) | AnalogGainToWrite); */
-       AnalogGainToWrite = (u16)((DigitalGain << 12) | (u16)AnalogGain);
-       ret = mt9m114_write_reg(client, MISENSOR_16BIT,
-                                       REG_GAIN, AnalogGainToWrite);
-       if (ret) {
-               v4l2_err(client, "%s: fail to set AnalogGainToWrite\n",
-                       __func__);
-               return -EINVAL;
-       }
-
-       return ret;
-}
-
-static long mt9m114_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
-{
-
-       switch (cmd) {
-       case ATOMISP_IOC_S_EXPOSURE:
-               return mt9m114_s_exposure(sd, arg);
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-/* This returns the exposure time being used. This should only be used
-   for filling in EXIF data, not for actual image processing. */
-static int mt9m114_g_exposure(struct v4l2_subdev *sd, s32 *value)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       u32 coarse;
-       int ret;
-
-       /* the fine integration time is currently not calculated */
-       ret = mt9m114_read_reg(client, MISENSOR_16BIT,
-                              REG_EXPO_COARSE, &coarse);
-       if (ret)
-               return ret;
-
-       *value = coarse;
-       return 0;
-}
-#ifndef CSS15
-/*
- * This function will return the sensor supported max exposure zone number.
- * the sensor which supports max exposure zone number is 1.
- */
-static int mt9m114_g_exposure_zone_num(struct v4l2_subdev *sd, s32 *val)
-{
-       *val = 1;
-
-       return 0;
-}
-
-/*
- * set exposure metering, average/center_weighted/spot/matrix.
- */
-static int mt9m114_s_exposure_metering(struct v4l2_subdev *sd, s32 val)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret;
-
-       switch (val) {
-       case V4L2_EXPOSURE_METERING_SPOT:
-               ret = mt9m114_write_reg_array(client, mt9m114_exp_average,
-                                               NO_POLLING);
-               if (ret) {
-                       dev_err(&client->dev, "write exp_average reg err.\n");
-                       return ret;
-               }
-               break;
-       case V4L2_EXPOSURE_METERING_CENTER_WEIGHTED:
-       default:
-               ret = mt9m114_write_reg_array(client, mt9m114_exp_center,
-                                               NO_POLLING);
-               if (ret) {
-                       dev_err(&client->dev, "write exp_default reg err");
-                       return ret;
-               }
-       }
-
-       return 0;
-}
-
-/*
- * This function is for touch exposure feature.
- */
-static int mt9m114_s_exposure_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 misensor_reg exp_reg;
-       int width, height;
-       int grid_width, grid_height;
-       int grid_left, grid_top, grid_right, grid_bottom;
-       int win_left, win_top, win_right, win_bottom;
-       int i, j;
-       int ret;
-
-       if (sel->which != V4L2_SUBDEV_FORMAT_TRY &&
-           sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
-               return -EINVAL;
-
-       grid_left = sel->r.left;
-       grid_top = sel->r.top;
-       grid_right = sel->r.left + sel->r.width - 1;
-       grid_bottom = sel->r.top + sel->r.height - 1;
-
-       ret = mt9m114_res2size(sd, &width, &height);
-       if (ret)
-               return ret;
-
-       grid_width = width / 5;
-       grid_height = height / 5;
-
-       if (grid_width && grid_height) {
-               win_left = grid_left / grid_width;
-               win_top = grid_top / grid_height;
-               win_right = grid_right / grid_width;
-               win_bottom = grid_bottom / grid_height;
-       } else {
-               dev_err(&client->dev, "Incorrect exp grid.\n");
-               return -EINVAL;
-       }
-
-       win_left   = clamp_t(int, win_left, 0, 4);
-       win_top    = clamp_t(int, win_top, 0, 4);
-       win_right  = clamp_t(int, win_right, 0, 4);
-       win_bottom = clamp_t(int, win_bottom, 0, 4);
-
-       ret = mt9m114_write_reg_array(client, mt9m114_exp_average, NO_POLLING);
-       if (ret) {
-               dev_err(&client->dev, "write exp_average reg err.\n");
-               return ret;
-       }
-
-       for (i = win_top; i <= win_bottom; i++) {
-               for (j = win_left; j <= win_right; j++) {
-                       exp_reg = mt9m114_exp_win[i][j];
-
-                       ret = mt9m114_write_reg(client, exp_reg.length,
-                                               exp_reg.reg, exp_reg.val);
-                       if (ret) {
-                               dev_err(&client->dev, "write exp_reg err.\n");
-                               return ret;
-                       }
-               }
-       }
-
-       return 0;
-}
-#endif
-
-static int mt9m114_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val)
-{
-       struct mt9m114_device *dev = to_mt9m114_sensor(sd);
-
-       *val = mt9m114_res[dev->res].bin_factor_x;
-
-       return 0;
-}
-
-static int mt9m114_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val)
-{
-       struct mt9m114_device *dev = to_mt9m114_sensor(sd);
-
-       *val = mt9m114_res[dev->res].bin_factor_y;
-
-       return 0;
-}
-
-static int mt9m114_s_ev(struct v4l2_subdev *sd, s32 val)
-{
-       struct i2c_client *c = v4l2_get_subdevdata(sd);
-       s32 luma = 0x37;
-       int err;
-
-       /* EV value only support -2 to 2
-        * 0: 0x37, 1:0x47, 2:0x57, -1:0x27, -2:0x17
-        */
-       if (val < -2 || val > 2)
-               return -EINVAL;
-       luma += 0x10 * val;
-       dev_dbg(&c->dev, "%s val:%d luma:0x%x\n", __func__, val, luma);
-       err = mt9m114_write_reg(c, MISENSOR_16BIT, 0x098E, 0xC87A);
-       if (err) {
-               dev_err(&c->dev, "%s logic addr access error\n", __func__);
-               return err;
-       }
-       err = mt9m114_write_reg(c, MISENSOR_8BIT, 0xC87A, (u32)luma);
-       if (err) {
-               dev_err(&c->dev, "%s write target_average_luma failed\n",
-                       __func__);
-               return err;
-       }
-       udelay(10);
-
-       return 0;
-}
-
-static int mt9m114_g_ev(struct v4l2_subdev *sd, s32 *val)
-{
-       struct i2c_client *c = v4l2_get_subdevdata(sd);
-       int err;
-       u32 luma;
-
-       err = mt9m114_write_reg(c, MISENSOR_16BIT, 0x098E, 0xC87A);
-       if (err) {
-               dev_err(&c->dev, "%s logic addr access error\n", __func__);
-               return err;
-       }
-       err = mt9m114_read_reg(c, MISENSOR_8BIT, 0xC87A, &luma);
-       if (err) {
-               dev_err(&c->dev, "%s read target_average_luma failed\n",
-                       __func__);
-               return err;
-       }
-       luma -= 0x17;
-       luma /= 0x10;
-       *val = (s32)luma - 2;
-       dev_dbg(&c->dev, "%s val:%d\n", __func__, *val);
-
-       return 0;
-}
-
-/* Fake interface
- * mt9m114 now can not support 3a_lock
-*/
-static int mt9m114_s_3a_lock(struct v4l2_subdev *sd, s32 val)
-{
-       aaalock = val;
-       return 0;
-}
-
-static int mt9m114_g_3a_lock(struct v4l2_subdev *sd, s32 *val)
-{
-       if (aaalock)
-               return V4L2_LOCK_EXPOSURE | V4L2_LOCK_WHITE_BALANCE
-                       | V4L2_LOCK_FOCUS;
-       return 0;
-}
-
-static int mt9m114_s_ctrl(struct v4l2_ctrl *ctrl)
-{
-       struct mt9m114_device *dev =
-           container_of(ctrl->handler, struct mt9m114_device, ctrl_handler);
-       struct i2c_client *client = v4l2_get_subdevdata(&dev->sd);
-       int ret = 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_VFLIP:
-               dev_dbg(&client->dev, "%s: CID_VFLIP:%d.\n",
-                       __func__, ctrl->val);
-               ret = mt9m114_t_vflip(&dev->sd, ctrl->val);
-               break;
-       case V4L2_CID_HFLIP:
-               dev_dbg(&client->dev, "%s: CID_HFLIP:%d.\n",
-                       __func__, ctrl->val);
-               ret = mt9m114_t_hflip(&dev->sd, ctrl->val);
-               break;
-#ifndef CSS15
-       case V4L2_CID_EXPOSURE_METERING:
-               ret = mt9m114_s_exposure_metering(&dev->sd, ctrl->val);
-               break;
-#endif
-       case V4L2_CID_EXPOSURE:
-               ret = mt9m114_s_ev(&dev->sd, ctrl->val);
-               break;
-       case V4L2_CID_3A_LOCK:
-               ret = mt9m114_s_3a_lock(&dev->sd, ctrl->val);
-               break;
-       default:
-               ret = -EINVAL;
-       }
-       return ret;
-}
-
-static int mt9m114_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
-{
-       struct mt9m114_device *dev =
-           container_of(ctrl->handler, struct mt9m114_device, ctrl_handler);
-       int ret = 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_VFLIP:
-               ret = mt9m114_g_vflip(&dev->sd, &ctrl->val);
-               break;
-       case V4L2_CID_HFLIP:
-               ret = mt9m114_g_hflip(&dev->sd, &ctrl->val);
-               break;
-       case V4L2_CID_FOCAL_ABSOLUTE:
-               ret = mt9m114_g_focal(&dev->sd, &ctrl->val);
-               break;
-       case V4L2_CID_FNUMBER_ABSOLUTE:
-               ret = mt9m114_g_fnumber(&dev->sd, &ctrl->val);
-               break;
-       case V4L2_CID_FNUMBER_RANGE:
-               ret = mt9m114_g_fnumber_range(&dev->sd, &ctrl->val);
-               break;
-       case V4L2_CID_EXPOSURE_ABSOLUTE:
-               ret = mt9m114_g_exposure(&dev->sd, &ctrl->val);
-               break;
-#ifndef CSS15
-       case V4L2_CID_EXPOSURE_ZONE_NUM:
-               ret = mt9m114_g_exposure_zone_num(&dev->sd, &ctrl->val);
-               break;
-#endif
-       case V4L2_CID_BIN_FACTOR_HORZ:
-               ret = mt9m114_g_bin_factor_x(&dev->sd, &ctrl->val);
-               break;
-       case V4L2_CID_BIN_FACTOR_VERT:
-               ret = mt9m114_g_bin_factor_y(&dev->sd, &ctrl->val);
-               break;
-       case V4L2_CID_EXPOSURE:
-               ret = mt9m114_g_ev(&dev->sd, &ctrl->val);
-               break;
-       case V4L2_CID_3A_LOCK:
-               ret = mt9m114_g_3a_lock(&dev->sd, &ctrl->val);
-               break;
-       default:
-               ret = -EINVAL;
-       }
-
-       return ret;
-}
-
-static const struct v4l2_ctrl_ops ctrl_ops = {
-       .s_ctrl = mt9m114_s_ctrl,
-       .g_volatile_ctrl = mt9m114_g_volatile_ctrl
-};
-
-static struct v4l2_ctrl_config mt9m114_controls[] = {
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_VFLIP,
-        .name = "Image v-Flip",
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .min = 0,
-        .max = 1,
-        .step = 1,
-        .def = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_HFLIP,
-        .name = "Image h-Flip",
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .min = 0,
-        .max = 1,
-        .step = 1,
-        .def = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_FOCAL_ABSOLUTE,
-        .name = "focal length",
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .min = MT9M114_FOCAL_LENGTH_DEFAULT,
-        .max = MT9M114_FOCAL_LENGTH_DEFAULT,
-        .step = 1,
-        .def = MT9M114_FOCAL_LENGTH_DEFAULT,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_FNUMBER_ABSOLUTE,
-        .name = "f-number",
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .min = MT9M114_F_NUMBER_DEFAULT,
-        .max = MT9M114_F_NUMBER_DEFAULT,
-        .step = 1,
-        .def = MT9M114_F_NUMBER_DEFAULT,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_FNUMBER_RANGE,
-        .name = "f-number range",
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .min = MT9M114_F_NUMBER_RANGE,
-        .max = MT9M114_F_NUMBER_RANGE,
-        .step = 1,
-        .def = MT9M114_F_NUMBER_RANGE,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_EXPOSURE_ABSOLUTE,
-        .name = "exposure",
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .min = 0,
-        .max = 0xffff,
-        .step = 1,
-        .def = 0,
-        .flags = 0,
-        },
-#ifndef CSS15
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_EXPOSURE_ZONE_NUM,
-        .name = "one-time exposure zone number",
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .min = 0,
-        .max = 0xffff,
-        .step = 1,
-        .def = 0,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_EXPOSURE_METERING,
-        .name = "metering",
-        .type = V4L2_CTRL_TYPE_MENU,
-        .min = 0,
-        .max = 3,
-        .step = 0,
-        .def = 1,
-        .flags = 0,
-        },
-#endif
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_BIN_FACTOR_HORZ,
-        .name = "horizontal binning factor",
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .min = 0,
-        .max = MT9M114_BIN_FACTOR_MAX,
-        .step = 1,
-        .def = 0,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_BIN_FACTOR_VERT,
-        .name = "vertical binning factor",
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .min = 0,
-        .max = MT9M114_BIN_FACTOR_MAX,
-        .step = 1,
-        .def = 0,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_EXPOSURE,
-        .name = "exposure biasx",
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .min = -2,
-        .max = 2,
-        .step = 1,
-        .def = 0,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_3A_LOCK,
-        .name = "3a lock",
-        .type = V4L2_CTRL_TYPE_BITMASK,
-        .min = 0,
-        .max = V4L2_LOCK_EXPOSURE | V4L2_LOCK_WHITE_BALANCE | V4L2_LOCK_FOCUS,
-        .step = 1,
-        .def = 0,
-        .flags = 0,
-        },
-};
-
-static int mt9m114_detect(struct mt9m114_device *dev, struct i2c_client *client)
-{
-       struct i2c_adapter *adapter = client->adapter;
-       u32 retvalue;
-
-       if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
-               dev_err(&client->dev, "%s: i2c error", __func__);
-               return -ENODEV;
-       }
-       mt9m114_read_reg(client, MISENSOR_16BIT, (u32)MT9M114_PID, &retvalue);
-       dev->real_model_id = retvalue;
-
-       if (retvalue != MT9M114_MOD_ID) {
-               dev_err(&client->dev, "%s: failed: client->addr = %x\n",
-                       __func__, client->addr);
-               return -ENODEV;
-       }
-
-       return 0;
-}
-
-static int
-mt9m114_s_config(struct v4l2_subdev *sd, int irq, void *platform_data)
-{
-       struct mt9m114_device *dev = to_mt9m114_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret;
-
-       if (NULL == platform_data)
-               return -ENODEV;
-
-       dev->platform_data =
-           (struct camera_sensor_platform_data *)platform_data;
-
-       if (dev->platform_data->platform_init) {
-               ret = dev->platform_data->platform_init(client);
-               if (ret) {
-                       v4l2_err(client, "mt9m114 platform init err\n");
-                       return ret;
-               }
-       }
-       ret = power_up(sd);
-       if (ret) {
-               v4l2_err(client, "mt9m114 power-up err");
-               return ret;
-       }
-
-       /* config & detect sensor */
-       ret = mt9m114_detect(dev, client);
-       if (ret) {
-               v4l2_err(client, "mt9m114_detect err s_config.\n");
-               goto fail_detect;
-       }
-
-       ret = dev->platform_data->csi_cfg(sd, 1);
-       if (ret)
-               goto fail_csi_cfg;
-
-       ret = mt9m114_set_suspend(sd);
-       if (ret) {
-               v4l2_err(client, "mt9m114 suspend err");
-               return ret;
-       }
-
-       ret = power_down(sd);
-       if (ret) {
-               v4l2_err(client, "mt9m114 power down err");
-               return ret;
-       }
-
-       return ret;
-
-fail_csi_cfg:
-       dev->platform_data->csi_cfg(sd, 0);
-fail_detect:
-       power_down(sd);
-       dev_err(&client->dev, "sensor power-gating failed\n");
-       return ret;
-}
-
-/* Horizontal flip the image. */
-static int mt9m114_t_hflip(struct v4l2_subdev *sd, int value)
-{
-       struct i2c_client *c = v4l2_get_subdevdata(sd);
-       struct mt9m114_device *dev = to_mt9m114_sensor(sd);
-       int err;
-       /* set for direct mode */
-       err = mt9m114_write_reg(c, MISENSOR_16BIT, 0x098E, 0xC850);
-       if (value) {
-               /* enable H flip ctx A */
-               err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC850, 0x01, 0x01);
-               err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC851, 0x01, 0x01);
-               /* ctx B */
-               err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC888, 0x01, 0x01);
-               err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC889, 0x01, 0x01);
-
-               err += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE,
-                                       MISENSOR_HFLIP_MASK, MISENSOR_FLIP_EN);
-
-               dev->bpat = MT9M114_BPAT_GRGRBGBG;
-       } else {
-               /* disable H flip ctx A */
-               err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC850, 0x01, 0x00);
-               err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC851, 0x01, 0x00);
-               /* ctx B */
-               err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC888, 0x01, 0x00);
-               err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC889, 0x01, 0x00);
-
-               err += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE,
-                                       MISENSOR_HFLIP_MASK, MISENSOR_FLIP_DIS);
-
-               dev->bpat = MT9M114_BPAT_BGBGGRGR;
-       }
-
-       err += mt9m114_write_reg(c, MISENSOR_8BIT, 0x8404, 0x06);
-       udelay(10);
-
-       return !!err;
-}
-
-/* Vertically flip the image */
-static int mt9m114_t_vflip(struct v4l2_subdev *sd, int value)
-{
-       struct i2c_client *c = v4l2_get_subdevdata(sd);
-       int err;
-       /* set for direct mode */
-       err = mt9m114_write_reg(c, MISENSOR_16BIT, 0x098E, 0xC850);
-       if (value >= 1) {
-               /* enable H flip - ctx A */
-               err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC850, 0x02, 0x01);
-               err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC851, 0x02, 0x01);
-               /* ctx B */
-               err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC888, 0x02, 0x01);
-               err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC889, 0x02, 0x01);
-
-               err += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE,
-                                       MISENSOR_VFLIP_MASK, MISENSOR_FLIP_EN);
-       } else {
-               /* disable H flip - ctx A */
-               err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC850, 0x02, 0x00);
-               err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC851, 0x02, 0x00);
-               /* ctx B */
-               err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC888, 0x02, 0x00);
-               err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC889, 0x02, 0x00);
-
-               err += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE,
-                                       MISENSOR_VFLIP_MASK, MISENSOR_FLIP_DIS);
-       }
-
-       err += mt9m114_write_reg(c, MISENSOR_8BIT, 0x8404, 0x06);
-       udelay(10);
-
-       return !!err;
-}
-static int mt9m114_s_parm(struct v4l2_subdev *sd,
-                       struct v4l2_streamparm *param)
-{
-       return 0;
-}
-
-static int mt9m114_g_frame_interval(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_frame_interval *interval)
-{
-       struct mt9m114_device *dev = to_mt9m114_sensor(sd);
-
-       interval->interval.numerator = 1;
-       interval->interval.denominator = mt9m114_res[dev->res].fps;
-
-       return 0;
-}
-
-static int mt9m114_s_stream(struct v4l2_subdev *sd, int enable)
-{
-       int ret;
-       struct i2c_client *c = v4l2_get_subdevdata(sd);
-       struct mt9m114_device *dev = to_mt9m114_sensor(sd);
-       struct atomisp_exposure exposure;
-
-       if (enable) {
-               ret = mt9m114_write_reg_array(c, mt9m114_chgstat_reg,
-                                       POST_POLLING);
-               if (ret < 0)
-                       return ret;
-
-               if (dev->first_exp > MT9M114_MAX_FIRST_EXP) {
-                       exposure.integration_time[0] = dev->first_exp;
-                       exposure.gain[0] = dev->first_gain;
-                       exposure.gain[1] = dev->first_diggain;
-                       mt9m114_s_exposure(sd, &exposure);
-               }
-               dev->streamon = 1;
-
-       } else {
-               dev->streamon = 0;
-               ret = mt9m114_set_suspend(sd);
-       }
-
-       return ret;
-}
-
-static int mt9m114_enum_mbus_code(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
-                                 struct v4l2_subdev_mbus_code_enum *code)
-{
-       if (code->index)
-               return -EINVAL;
-       code->code = MEDIA_BUS_FMT_SGRBG10_1X10;
-
-       return 0;
-}
-
-static int mt9m114_enum_frame_size(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_pad_config *cfg,
-                                  struct v4l2_subdev_frame_size_enum *fse)
-{
-
-       unsigned int index = fse->index;
-
-       if (index >= N_RES)
-               return -EINVAL;
-
-       fse->min_width = mt9m114_res[index].width;
-       fse->min_height = mt9m114_res[index].height;
-       fse->max_width = mt9m114_res[index].width;
-       fse->max_height = mt9m114_res[index].height;
-
-       return 0;
-}
-
-static int mt9m114_g_skip_frames(struct v4l2_subdev *sd, u32 *frames)
-{
-       int index;
-       struct mt9m114_device *snr = to_mt9m114_sensor(sd);
-
-       if (frames == NULL)
-               return -EINVAL;
-
-       for (index = 0; index < N_RES; index++) {
-               if (mt9m114_res[index].res == snr->res)
-                       break;
-       }
-
-       if (index >= N_RES)
-               return -EINVAL;
-
-       *frames = mt9m114_res[index].skip_frames;
-
-       return 0;
-}
-
-static const struct v4l2_subdev_video_ops mt9m114_video_ops = {
-       .s_parm = mt9m114_s_parm,
-       .s_stream = mt9m114_s_stream,
-       .g_frame_interval = mt9m114_g_frame_interval,
-};
-
-static const struct v4l2_subdev_sensor_ops mt9m114_sensor_ops = {
-       .g_skip_frames  = mt9m114_g_skip_frames,
-};
-
-static const struct v4l2_subdev_core_ops mt9m114_core_ops = {
-       .s_power = mt9m114_s_power,
-       .ioctl = mt9m114_ioctl,
-};
-
-/* REVISIT: Do we need pad operations? */
-static const struct v4l2_subdev_pad_ops mt9m114_pad_ops = {
-       .enum_mbus_code = mt9m114_enum_mbus_code,
-       .enum_frame_size = mt9m114_enum_frame_size,
-       .get_fmt = mt9m114_get_fmt,
-       .set_fmt = mt9m114_set_fmt,
-#ifndef CSS15
-       .set_selection = mt9m114_s_exposure_selection,
-#endif
-};
-
-static const struct v4l2_subdev_ops mt9m114_ops = {
-       .core = &mt9m114_core_ops,
-       .video = &mt9m114_video_ops,
-       .pad = &mt9m114_pad_ops,
-       .sensor = &mt9m114_sensor_ops,
-};
-
-static const struct media_entity_operations mt9m114_entity_ops = {
-       .link_setup = NULL,
-};
-
-static int mt9m114_remove(struct i2c_client *client)
-{
-       struct mt9m114_device *dev;
-       struct v4l2_subdev *sd = i2c_get_clientdata(client);
-
-       dev = container_of(sd, struct mt9m114_device, sd);
-       dev->platform_data->csi_cfg(sd, 0);
-       if (dev->platform_data->platform_deinit)
-               dev->platform_data->platform_deinit();
-       v4l2_device_unregister_subdev(sd);
-       media_entity_cleanup(&dev->sd.entity);
-       v4l2_ctrl_handler_free(&dev->ctrl_handler);
-       kfree(dev);
-       return 0;
-}
-
-static int mt9m114_probe(struct i2c_client *client,
-                      const struct i2c_device_id *id)
-{
-       struct mt9m114_device *dev;
-       int ret = 0;
-       unsigned int i;
-       void *pdata;
-
-       /* Setup sensor configuration structure */
-       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-       if (!dev) {
-               dev_err(&client->dev, "out of memory\n");
-               return -ENOMEM;
-       }
-
-       v4l2_i2c_subdev_init(&dev->sd, client, &mt9m114_ops);
-       pdata = client->dev.platform_data;
-       if (ACPI_COMPANION(&client->dev))
-               pdata = gmin_camera_platform_data(&dev->sd,
-                                                 ATOMISP_INPUT_FORMAT_RAW_10,
-                                                 atomisp_bayer_order_grbg);
-       if (pdata)
-               ret = mt9m114_s_config(&dev->sd, client->irq, pdata);
-       if (!pdata || ret) {
-               v4l2_device_unregister_subdev(&dev->sd);
-               kfree(dev);
-               return ret;
-       }
-
-       ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA);
-       if (ret) {
-               v4l2_device_unregister_subdev(&dev->sd);
-               kfree(dev);
-               /* Coverity CID 298095 - return on error */
-               return ret;
-       }
-
-       /*TODO add format code here*/
-       dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-       dev->pad.flags = MEDIA_PAD_FL_SOURCE;
-       dev->format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
-       dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
-
-       ret =
-           v4l2_ctrl_handler_init(&dev->ctrl_handler,
-                                  ARRAY_SIZE(mt9m114_controls));
-       if (ret) {
-               mt9m114_remove(client);
-               return ret;
-       }
-
-       for (i = 0; i < ARRAY_SIZE(mt9m114_controls); i++)
-               v4l2_ctrl_new_custom(&dev->ctrl_handler, &mt9m114_controls[i],
-                                    NULL);
-
-       if (dev->ctrl_handler.error) {
-               mt9m114_remove(client);
-               return dev->ctrl_handler.error;
-       }
-
-       /* Use same lock for controls as for everything else. */
-       dev->ctrl_handler.lock = &dev->input_lock;
-       dev->sd.ctrl_handler = &dev->ctrl_handler;
-
-       /* REVISIT: Do we need media controller? */
-       ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad);
-       if (ret) {
-               mt9m114_remove(client);
-               return ret;
-       }
-       return 0;
-}
-
-MODULE_DEVICE_TABLE(i2c, mt9m114_id);
-
-static const struct acpi_device_id mt9m114_acpi_match[] = {
-       { "INT33F0" },
-       { "CRMT1040" },
-       {},
-};
-
-MODULE_DEVICE_TABLE(acpi, mt9m114_acpi_match);
-
-static struct i2c_driver mt9m114_driver = {
-       .driver = {
-               .name = "mt9m114",
-               .acpi_match_table = ACPI_PTR(mt9m114_acpi_match),
-       },
-       .probe = mt9m114_probe,
-       .remove = mt9m114_remove,
-       .id_table = mt9m114_id,
-};
-
-static __init int init_mt9m114(void)
-{
-       return i2c_add_driver(&mt9m114_driver);
-}
-
-static __exit void exit_mt9m114(void)
-{
-       i2c_del_driver(&mt9m114_driver);
-}
-
-module_init(init_mt9m114);
-module_exit(exit_mt9m114);
-
-MODULE_AUTHOR("Shuguang Gong <Shuguang.gong@intel.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/media/atomisp/i2c/ov2680.c b/drivers/staging/media/atomisp/i2c/ov2680.c
deleted file mode 100644 (file)
index 51b7d61..0000000
+++ /dev/null
@@ -1,1557 +0,0 @@
-/*
- * Support for OmniVision OV2680 1080p HD camera sensor.
- *
- * Copyright (c) 2013 Intel Corporation. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/kmod.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/gpio.h>
-#include <linux/moduleparam.h>
-#include <media/v4l2-device.h>
-#include <linux/io.h>
-#include <linux/acpi.h>
-#include "../include/linux/atomisp_gmin_platform.h"
-
-#include "ov2680.h"
-
-static int h_flag = 0;
-static int v_flag = 0;
-static enum atomisp_bayer_order ov2680_bayer_order_mapping[] = {
-       atomisp_bayer_order_bggr,
-       atomisp_bayer_order_grbg,
-       atomisp_bayer_order_gbrg,
-       atomisp_bayer_order_rggb,
-};
-
-/* i2c read/write stuff */
-static int ov2680_read_reg(struct i2c_client *client,
-                          u16 data_length, u16 reg, u16 *val)
-{
-       int err;
-       struct i2c_msg msg[2];
-       unsigned char data[6];
-
-       if (!client->adapter) {
-               dev_err(&client->dev, "%s error, no client->adapter\n",
-                       __func__);
-               return -ENODEV;
-       }
-
-       if (data_length != OV2680_8BIT && data_length != OV2680_16BIT
-                                       && data_length != OV2680_32BIT) {
-               dev_err(&client->dev, "%s error, invalid data length\n",
-                       __func__);
-               return -EINVAL;
-       }
-
-       memset(msg, 0 , sizeof(msg));
-
-       msg[0].addr = client->addr;
-       msg[0].flags = 0;
-       msg[0].len = I2C_MSG_LENGTH;
-       msg[0].buf = data;
-
-       /* high byte goes out first */
-       data[0] = (u8)(reg >> 8);
-       data[1] = (u8)(reg & 0xff);
-
-       msg[1].addr = client->addr;
-       msg[1].len = data_length;
-       msg[1].flags = I2C_M_RD;
-       msg[1].buf = data;
-
-       err = i2c_transfer(client->adapter, msg, 2);
-       if (err != 2) {
-               if (err >= 0)
-                       err = -EIO;
-               dev_err(&client->dev,
-                       "read from offset 0x%x error %d", reg, err);
-               return err;
-       }
-
-       *val = 0;
-       /* high byte comes first */
-       if (data_length == OV2680_8BIT)
-               *val = (u8)data[0];
-       else if (data_length == OV2680_16BIT)
-               *val = be16_to_cpu(*(u16 *)&data[0]);
-       else
-               *val = be32_to_cpu(*(u32 *)&data[0]);
-       //dev_dbg(&client->dev,  "++++i2c read adr%x = %x\n", reg,*val);
-       return 0;
-}
-
-static int ov2680_i2c_write(struct i2c_client *client, u16 len, u8 *data)
-{
-       struct i2c_msg msg;
-       const int num_msg = 1;
-       int ret;
-
-       msg.addr = client->addr;
-       msg.flags = 0;
-       msg.len = len;
-       msg.buf = data;
-       ret = i2c_transfer(client->adapter, &msg, 1);
-       //dev_dbg(&client->dev,  "+++i2c write reg=%x->%x\n", data[0]*256 +data[1],data[2]);
-       return ret == num_msg ? 0 : -EIO;
-}
-
-static int ov2680_write_reg(struct i2c_client *client, u16 data_length,
-                                                       u16 reg, u16 val)
-{
-       int ret;
-       unsigned char data[4] = {0};
-       u16 *wreg = (u16 *)data;
-       const u16 len = data_length + sizeof(u16); /* 16-bit address + data */
-
-       if (data_length != OV2680_8BIT && data_length != OV2680_16BIT) {
-               dev_err(&client->dev,
-                       "%s error, invalid data_length\n", __func__);
-               return -EINVAL;
-       }
-
-       /* high byte goes out first */
-       *wreg = cpu_to_be16(reg);
-
-       if (data_length == OV2680_8BIT) {
-               data[2] = (u8)(val);
-       } else {
-               /* OV2680_16BIT */
-               u16 *wdata = (u16 *)&data[2];
-               *wdata = cpu_to_be16(val);
-       }
-
-       ret = ov2680_i2c_write(client, len, data);
-       if (ret)
-               dev_err(&client->dev,
-                       "write error: wrote 0x%x to offset 0x%x error %d",
-                       val, reg, ret);
-
-       return ret;
-}
-
-/*
- * ov2680_write_reg_array - Initializes a list of OV2680 registers
- * @client: i2c driver client structure
- * @reglist: list of registers to be written
- *
- * This function initializes a list of registers. When consecutive addresses
- * are found in a row on the list, this function creates a buffer and sends
- * consecutive data in a single i2c_transfer().
- *
- * __ov2680_flush_reg_array, __ov2680_buf_reg_array() and
- * __ov2680_write_reg_is_consecutive() are internal functions to
- * ov2680_write_reg_array_fast() and should be not used anywhere else.
- *
- */
-
-static int __ov2680_flush_reg_array(struct i2c_client *client,
-                                   struct ov2680_write_ctrl *ctrl)
-{
-       u16 size;
-
-       if (ctrl->index == 0)
-               return 0;
-
-       size = sizeof(u16) + ctrl->index; /* 16-bit address + data */
-       ctrl->buffer.addr = cpu_to_be16(ctrl->buffer.addr);
-       ctrl->index = 0;
-
-       return ov2680_i2c_write(client, size, (u8 *)&ctrl->buffer);
-}
-
-static int __ov2680_buf_reg_array(struct i2c_client *client,
-                                 struct ov2680_write_ctrl *ctrl,
-                                 const struct ov2680_reg *next)
-{
-       int size;
-       u16 *data16;
-
-       switch (next->type) {
-       case OV2680_8BIT:
-               size = 1;
-               ctrl->buffer.data[ctrl->index] = (u8)next->val;
-               break;
-       case OV2680_16BIT:
-               size = 2;
-               data16 = (u16 *)&ctrl->buffer.data[ctrl->index];
-               *data16 = cpu_to_be16((u16)next->val);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       /* When first item is added, we need to store its starting address */
-       if (ctrl->index == 0)
-               ctrl->buffer.addr = next->reg;
-
-       ctrl->index += size;
-
-       /*
-        * Buffer cannot guarantee free space for u32? Better flush it to avoid
-        * possible lack of memory for next item.
-        */
-       if (ctrl->index + sizeof(u16) >= OV2680_MAX_WRITE_BUF_SIZE)
-               return __ov2680_flush_reg_array(client, ctrl);
-
-       return 0;
-}
-
-static int __ov2680_write_reg_is_consecutive(struct i2c_client *client,
-                                            struct ov2680_write_ctrl *ctrl,
-                                            const struct ov2680_reg *next)
-{
-       if (ctrl->index == 0)
-               return 1;
-
-       return ctrl->buffer.addr + ctrl->index == next->reg;
-}
-
-static int ov2680_write_reg_array(struct i2c_client *client,
-                                 const struct ov2680_reg *reglist)
-{
-       const struct ov2680_reg *next = reglist;
-       struct ov2680_write_ctrl ctrl;
-       int err;
-       dev_dbg(&client->dev,  "++++write reg array\n");
-       ctrl.index = 0;
-       for (; next->type != OV2680_TOK_TERM; next++) {
-               switch (next->type & OV2680_TOK_MASK) {
-               case OV2680_TOK_DELAY:
-                       err = __ov2680_flush_reg_array(client, &ctrl);
-                       if (err)
-                               return err;
-                       msleep(next->val);
-                       break;
-               default:
-                       /*
-                        * If next address is not consecutive, data needs to be
-                        * flushed before proceed.
-                        */
-                        dev_dbg(&client->dev,  "+++ov2680_write_reg_array reg=%x->%x\n", next->reg,next->val);
-                       if (!__ov2680_write_reg_is_consecutive(client, &ctrl,
-                                                               next)) {
-                               err = __ov2680_flush_reg_array(client, &ctrl);
-                       if (err)
-                               return err;
-                       }
-                       err = __ov2680_buf_reg_array(client, &ctrl, next);
-                       if (err) {
-                               dev_err(&client->dev, "%s: write error, aborted\n",
-                                        __func__);
-                               return err;
-                       }
-                       break;
-               }
-       }
-
-       return __ov2680_flush_reg_array(client, &ctrl);
-}
-static int ov2680_g_focal(struct v4l2_subdev *sd, s32 *val)
-{
-
-       *val = (OV2680_FOCAL_LENGTH_NUM << 16) | OV2680_FOCAL_LENGTH_DEM;
-       return 0;
-}
-
-static int ov2680_g_fnumber(struct v4l2_subdev *sd, s32 *val)
-{
-       /*const f number for ov2680*/
-
-       *val = (OV2680_F_NUMBER_DEFAULT_NUM << 16) | OV2680_F_NUMBER_DEM;
-       return 0;
-}
-
-static int ov2680_g_fnumber_range(struct v4l2_subdev *sd, s32 *val)
-{
-       *val = (OV2680_F_NUMBER_DEFAULT_NUM << 24) |
-               (OV2680_F_NUMBER_DEM << 16) |
-               (OV2680_F_NUMBER_DEFAULT_NUM << 8) | OV2680_F_NUMBER_DEM;
-       return 0;
-}
-
-static int ov2680_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val)
-{
-       struct ov2680_device *dev = to_ov2680_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       dev_dbg(&client->dev,  "++++ov2680_g_bin_factor_x\n");
-       *val = ov2680_res[dev->fmt_idx].bin_factor_x;
-
-       return 0;
-}
-
-static int ov2680_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val)
-{
-       struct ov2680_device *dev = to_ov2680_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       *val = ov2680_res[dev->fmt_idx].bin_factor_y;
-       dev_dbg(&client->dev,  "++++ov2680_g_bin_factor_y\n");
-       return 0;
-}
-
-
-static int ov2680_get_intg_factor(struct i2c_client *client,
-                               struct camera_mipi_info *info,
-                               const struct ov2680_resolution *res)
-{
-       struct v4l2_subdev *sd = i2c_get_clientdata(client);
-       struct ov2680_device *dev = to_ov2680_sensor(sd);
-       struct atomisp_sensor_mode_data *buf = &info->data;
-       unsigned int pix_clk_freq_hz;
-       u16 reg_val;
-       int ret;
-       dev_dbg(&client->dev,  "++++ov2680_get_intg_factor\n");
-       if (!info)
-               return -EINVAL;
-
-       /* pixel clock */
-       pix_clk_freq_hz = res->pix_clk_freq * 1000000;
-
-       dev->vt_pix_clk_freq_mhz = pix_clk_freq_hz;
-       buf->vt_pix_clk_freq_mhz = pix_clk_freq_hz;
-
-       /* get integration time */
-       buf->coarse_integration_time_min = OV2680_COARSE_INTG_TIME_MIN;
-       buf->coarse_integration_time_max_margin =
-                                       OV2680_COARSE_INTG_TIME_MAX_MARGIN;
-
-       buf->fine_integration_time_min = OV2680_FINE_INTG_TIME_MIN;
-       buf->fine_integration_time_max_margin =
-                                       OV2680_FINE_INTG_TIME_MAX_MARGIN;
-
-       buf->fine_integration_time_def = OV2680_FINE_INTG_TIME_MIN;
-       buf->frame_length_lines = res->lines_per_frame;
-       buf->line_length_pck = res->pixels_per_line;
-       buf->read_mode = res->bin_mode;
-
-       /* get the cropping and output resolution to ISP for this mode. */
-       ret =  ov2680_read_reg(client, OV2680_16BIT,
-                                       OV2680_HORIZONTAL_START_H, &reg_val);
-       if (ret)
-               return ret;
-       buf->crop_horizontal_start = reg_val;
-
-       ret =  ov2680_read_reg(client, OV2680_16BIT,
-                                       OV2680_VERTICAL_START_H, &reg_val);
-       if (ret)
-               return ret;
-       buf->crop_vertical_start = reg_val;
-
-       ret = ov2680_read_reg(client, OV2680_16BIT,
-                                       OV2680_HORIZONTAL_END_H, &reg_val);
-       if (ret)
-               return ret;
-       buf->crop_horizontal_end = reg_val;
-
-       ret = ov2680_read_reg(client, OV2680_16BIT,
-                                       OV2680_VERTICAL_END_H, &reg_val);
-       if (ret)
-               return ret;
-       buf->crop_vertical_end = reg_val;
-
-       ret = ov2680_read_reg(client, OV2680_16BIT,
-                                       OV2680_HORIZONTAL_OUTPUT_SIZE_H, &reg_val);
-       if (ret)
-               return ret;
-       buf->output_width = reg_val;
-
-       ret = ov2680_read_reg(client, OV2680_16BIT,
-                                       OV2680_VERTICAL_OUTPUT_SIZE_H, &reg_val);
-       if (ret)
-               return ret;
-       buf->output_height = reg_val;
-
-       buf->binning_factor_x = res->bin_factor_x ?
-                                       (res->bin_factor_x * 2) : 1;
-       buf->binning_factor_y = res->bin_factor_y ?
-                                       (res->bin_factor_y * 2) : 1;
-       return 0;
-}
-
-static long __ov2680_set_exposure(struct v4l2_subdev *sd, int coarse_itg,
-                                int gain, int digitgain)
-
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct ov2680_device *dev = to_ov2680_sensor(sd);
-       u16 vts,hts;
-       int ret,exp_val;
-
-       dev_dbg(&client->dev, "+++++++__ov2680_set_exposure coarse_itg %d, gain %d, digitgain %d++\n",coarse_itg, gain, digitgain);
-
-       hts = ov2680_res[dev->fmt_idx].pixels_per_line;
-       vts = ov2680_res[dev->fmt_idx].lines_per_frame;
-
-       /* group hold */
-       ret = ov2680_write_reg(client, OV2680_8BIT,
-                                       OV2680_GROUP_ACCESS, 0x00);
-       if (ret) {
-               dev_err(&client->dev, "%s: write %x error, aborted\n",
-                       __func__, OV2680_GROUP_ACCESS);
-               return ret;
-       }
-
-       /* Increase the VTS to match exposure + MARGIN */
-       if (coarse_itg > vts - OV2680_INTEGRATION_TIME_MARGIN)
-               vts = (u16) coarse_itg + OV2680_INTEGRATION_TIME_MARGIN;
-
-       ret = ov2680_write_reg(client, OV2680_16BIT, OV2680_TIMING_VTS_H, vts);
-       if (ret) {
-               dev_err(&client->dev, "%s: write %x error, aborted\n",
-                       __func__, OV2680_TIMING_VTS_H);
-               return ret;
-       }
-
-       /* set exposure */
-
-       /* Lower four bit should be 0*/
-       exp_val = coarse_itg << 4;
-       ret = ov2680_write_reg(client, OV2680_8BIT,
-                              OV2680_EXPOSURE_L, exp_val & 0xFF);
-       if (ret) {
-               dev_err(&client->dev, "%s: write %x error, aborted\n",
-                       __func__, OV2680_EXPOSURE_L);
-               return ret;
-       }
-
-       ret = ov2680_write_reg(client, OV2680_8BIT,
-                              OV2680_EXPOSURE_M, (exp_val >> 8) & 0xFF);
-       if (ret) {
-               dev_err(&client->dev, "%s: write %x error, aborted\n",
-                       __func__, OV2680_EXPOSURE_M);
-               return ret;
-       }
-
-       ret = ov2680_write_reg(client, OV2680_8BIT,
-                              OV2680_EXPOSURE_H, (exp_val >> 16) & 0x0F);
-       if (ret) {
-               dev_err(&client->dev, "%s: write %x error, aborted\n",
-                       __func__, OV2680_EXPOSURE_H);
-               return ret;
-       }
-
-       /* Analog gain */
-       ret = ov2680_write_reg(client, OV2680_16BIT, OV2680_AGC_H, gain);
-       if (ret) {
-               dev_err(&client->dev, "%s: write %x error, aborted\n",
-                       __func__, OV2680_AGC_H);
-               return ret;
-       }
-       /* Digital gain */
-       if (digitgain) {
-               ret = ov2680_write_reg(client, OV2680_16BIT,
-                               OV2680_MWB_RED_GAIN_H, digitgain);
-               if (ret) {
-                       dev_err(&client->dev, "%s: write %x error, aborted\n",
-                               __func__, OV2680_MWB_RED_GAIN_H);
-                       return ret;
-               }
-
-               ret = ov2680_write_reg(client, OV2680_16BIT,
-                               OV2680_MWB_GREEN_GAIN_H, digitgain);
-               if (ret) {
-                       dev_err(&client->dev, "%s: write %x error, aborted\n",
-                               __func__, OV2680_MWB_RED_GAIN_H);
-                       return ret;
-               }
-
-               ret = ov2680_write_reg(client, OV2680_16BIT,
-                               OV2680_MWB_BLUE_GAIN_H, digitgain);
-               if (ret) {
-                       dev_err(&client->dev, "%s: write %x error, aborted\n",
-                               __func__, OV2680_MWB_RED_GAIN_H);
-                       return ret;
-               }
-       }
-
-       /* End group */
-       ret = ov2680_write_reg(client, OV2680_8BIT,
-                              OV2680_GROUP_ACCESS, 0x10);
-       if (ret)
-               return ret;
-
-       /* Delay launch group */
-       ret = ov2680_write_reg(client, OV2680_8BIT,
-                                          OV2680_GROUP_ACCESS, 0xa0);
-       if (ret)
-               return ret;
-       return ret;
-}
-
-static int ov2680_set_exposure(struct v4l2_subdev *sd, int exposure,
-       int gain, int digitgain)
-{
-       struct ov2680_device *dev = to_ov2680_sensor(sd);
-       int ret;
-
-       mutex_lock(&dev->input_lock);
-       ret = __ov2680_set_exposure(sd, exposure, gain, digitgain);
-       mutex_unlock(&dev->input_lock);
-
-       return ret;
-}
-
-static long ov2680_s_exposure(struct v4l2_subdev *sd,
-                              struct atomisp_exposure *exposure)
-{
-       u16 coarse_itg = exposure->integration_time[0];
-       u16 analog_gain = exposure->gain[0];
-       u16 digital_gain = exposure->gain[1];
-
-       /* we should not accept the invalid value below */
-       if (analog_gain == 0) {
-               struct i2c_client *client = v4l2_get_subdevdata(sd);
-               v4l2_err(client, "%s: invalid value\n", __func__);
-               return -EINVAL;
-       }
-
-       // EXPOSURE CONTROL DISABLED FOR INITIAL CHECKIN, TUNING DOESN'T WORK
-       return ov2680_set_exposure(sd, coarse_itg, analog_gain, digital_gain);
-}
-
-
-
-
-
-static long ov2680_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
-{
-
-       switch (cmd) {
-       case ATOMISP_IOC_S_EXPOSURE:
-               return ov2680_s_exposure(sd, arg);
-
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-
-/* This returns the exposure time being used. This should only be used
- * for filling in EXIF data, not for actual image processing.
- */
-static int ov2680_q_exposure(struct v4l2_subdev *sd, s32 *value)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       u16 reg_v, reg_v2;
-       int ret;
-
-       /* get exposure */
-       ret = ov2680_read_reg(client, OV2680_8BIT,
-                                       OV2680_EXPOSURE_L,
-                                       &reg_v);
-       if (ret)
-               goto err;
-
-       ret = ov2680_read_reg(client, OV2680_8BIT,
-                                       OV2680_EXPOSURE_M,
-                                       &reg_v2);
-       if (ret)
-               goto err;
-
-       reg_v += reg_v2 << 8;
-       ret = ov2680_read_reg(client, OV2680_8BIT,
-                                       OV2680_EXPOSURE_H,
-                                       &reg_v2);
-       if (ret)
-               goto err;
-
-       *value = reg_v + (((u32)reg_v2 << 16));
-err:
-       return ret;
-}
-
-static u32 ov2680_translate_bayer_order(enum atomisp_bayer_order code)
-{
-       switch (code) {
-       case atomisp_bayer_order_rggb:
-               return MEDIA_BUS_FMT_SRGGB10_1X10;
-       case atomisp_bayer_order_grbg:
-               return MEDIA_BUS_FMT_SGRBG10_1X10;
-       case atomisp_bayer_order_bggr:
-               return MEDIA_BUS_FMT_SBGGR10_1X10;
-       case atomisp_bayer_order_gbrg:
-               return MEDIA_BUS_FMT_SGBRG10_1X10;
-       }
-       return 0;
-}
-
-static int ov2680_v_flip(struct v4l2_subdev *sd, s32 value)
-{
-       struct ov2680_device *dev = to_ov2680_sensor(sd);
-       struct camera_mipi_info *ov2680_info = NULL;
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret;
-       u16 val;
-       u8 index;
-       dev_dbg(&client->dev, "@%s: value:%d\n", __func__, value);
-       ret = ov2680_read_reg(client, OV2680_8BIT, OV2680_FLIP_REG, &val);
-       if (ret)
-               return ret;
-       if (value) {
-               val |= OV2680_FLIP_MIRROR_BIT_ENABLE;
-       } else {
-               val &= ~OV2680_FLIP_MIRROR_BIT_ENABLE;
-       }
-       ret = ov2680_write_reg(client, OV2680_8BIT,
-                       OV2680_FLIP_REG, val);
-       if (ret)
-               return ret;
-       index = (v_flag>0?OV2680_FLIP_BIT:0) | (h_flag>0?OV2680_MIRROR_BIT:0);
-       ov2680_info = v4l2_get_subdev_hostdata(sd);
-       if (ov2680_info) {
-               ov2680_info->raw_bayer_order = ov2680_bayer_order_mapping[index];
-               dev->format.code = ov2680_translate_bayer_order(
-                       ov2680_info->raw_bayer_order);
-       }
-       return ret;
-}
-
-static int ov2680_h_flip(struct v4l2_subdev *sd, s32 value)
-{
-       struct ov2680_device *dev = to_ov2680_sensor(sd);
-       struct camera_mipi_info *ov2680_info = NULL;
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret;
-       u16 val;
-       u8 index;
-       dev_dbg(&client->dev, "@%s: value:%d\n", __func__, value);
-
-       ret = ov2680_read_reg(client, OV2680_8BIT, OV2680_MIRROR_REG, &val);
-       if (ret)
-               return ret;
-       if (value) {
-               val |= OV2680_FLIP_MIRROR_BIT_ENABLE;
-       } else {
-               val &= ~OV2680_FLIP_MIRROR_BIT_ENABLE;
-       }
-       ret = ov2680_write_reg(client, OV2680_8BIT,
-                       OV2680_MIRROR_REG, val);
-       if (ret)
-               return ret;
-       index = (v_flag>0?OV2680_FLIP_BIT:0) | (h_flag>0?OV2680_MIRROR_BIT:0);
-       ov2680_info = v4l2_get_subdev_hostdata(sd);
-       if (ov2680_info) {
-               ov2680_info->raw_bayer_order = ov2680_bayer_order_mapping[index];
-               dev->format.code = ov2680_translate_bayer_order(
-                       ov2680_info->raw_bayer_order);
-       }
-       return ret;
-}
-
-static int ov2680_s_ctrl(struct v4l2_ctrl *ctrl)
-{
-       struct ov2680_device *dev =
-           container_of(ctrl->handler, struct ov2680_device, ctrl_handler);
-       struct i2c_client *client = v4l2_get_subdevdata(&dev->sd);
-       int ret = 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_VFLIP:
-               dev_dbg(&client->dev, "%s: CID_VFLIP:%d.\n",
-                       __func__, ctrl->val);
-               ret = ov2680_v_flip(&dev->sd, ctrl->val);
-               break;
-       case V4L2_CID_HFLIP:
-               dev_dbg(&client->dev, "%s: CID_HFLIP:%d.\n",
-                       __func__, ctrl->val);
-               ret = ov2680_h_flip(&dev->sd, ctrl->val);
-               break;
-       default:
-               ret = -EINVAL;
-       }
-       return ret;
-}
-
-static int ov2680_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
-{
-       struct ov2680_device *dev =
-           container_of(ctrl->handler, struct ov2680_device, ctrl_handler);
-       int ret = 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_EXPOSURE_ABSOLUTE:
-               ret = ov2680_q_exposure(&dev->sd, &ctrl->val);
-               break;
-       case V4L2_CID_FOCAL_ABSOLUTE:
-               ret = ov2680_g_focal(&dev->sd, &ctrl->val);
-               break;
-       case V4L2_CID_FNUMBER_ABSOLUTE:
-               ret = ov2680_g_fnumber(&dev->sd, &ctrl->val);
-               break;
-       case V4L2_CID_FNUMBER_RANGE:
-               ret = ov2680_g_fnumber_range(&dev->sd, &ctrl->val);
-               break;
-       case V4L2_CID_BIN_FACTOR_HORZ:
-               ret = ov2680_g_bin_factor_x(&dev->sd, &ctrl->val);
-               break;
-       case V4L2_CID_BIN_FACTOR_VERT:
-               ret = ov2680_g_bin_factor_y(&dev->sd, &ctrl->val);
-               break;
-       default:
-               ret = -EINVAL;
-       }
-
-       return ret;
-}
-
-static const struct v4l2_ctrl_ops ctrl_ops = {
-       .s_ctrl = ov2680_s_ctrl,
-       .g_volatile_ctrl = ov2680_g_volatile_ctrl
-};
-
-struct v4l2_ctrl_config ov2680_controls[] = {
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_EXPOSURE_ABSOLUTE,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .name = "exposure",
-        .min = 0x0,
-        .max = 0xffff,
-        .step = 0x01,
-        .def = 0x00,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_FOCAL_ABSOLUTE,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .name = "focal length",
-        .min = OV2680_FOCAL_LENGTH_DEFAULT,
-        .max = OV2680_FOCAL_LENGTH_DEFAULT,
-        .step = 0x01,
-        .def = OV2680_FOCAL_LENGTH_DEFAULT,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_FNUMBER_ABSOLUTE,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .name = "f-number",
-        .min = OV2680_F_NUMBER_DEFAULT,
-        .max = OV2680_F_NUMBER_DEFAULT,
-        .step = 0x01,
-        .def = OV2680_F_NUMBER_DEFAULT,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_FNUMBER_RANGE,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .name = "f-number range",
-        .min = OV2680_F_NUMBER_RANGE,
-        .max = OV2680_F_NUMBER_RANGE,
-        .step = 0x01,
-        .def = OV2680_F_NUMBER_RANGE,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_BIN_FACTOR_HORZ,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .name = "horizontal binning factor",
-        .min = 0,
-        .max = OV2680_BIN_FACTOR_MAX,
-        .step = 1,
-        .def = 0,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_BIN_FACTOR_VERT,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .name = "vertical binning factor",
-        .min = 0,
-        .max = OV2680_BIN_FACTOR_MAX,
-        .step = 1,
-        .def = 0,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_VFLIP,
-        .type = V4L2_CTRL_TYPE_BOOLEAN,
-        .name = "Flip",
-        .min = 0,
-        .max = 1,
-        .step = 1,
-        .def = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_HFLIP,
-        .type = V4L2_CTRL_TYPE_BOOLEAN,
-        .name = "Mirror",
-        .min = 0,
-        .max = 1,
-        .step = 1,
-        .def = 0,
-        },
-};
-
-static int ov2680_init_registers(struct v4l2_subdev *sd)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret;
-
-       ret = ov2680_write_reg(client, OV2680_8BIT, OV2680_SW_RESET, 0x01);
-       ret |= ov2680_write_reg_array(client, ov2680_global_setting);
-
-       return ret;
-}
-
-static int ov2680_init(struct v4l2_subdev *sd)
-{
-       struct ov2680_device *dev = to_ov2680_sensor(sd);
-
-       int ret;
-
-       mutex_lock(&dev->input_lock);
-
-       /* restore settings */
-       ov2680_res = ov2680_res_preview;
-       N_RES = N_RES_PREVIEW;
-
-       ret = ov2680_init_registers(sd);
-
-       mutex_unlock(&dev->input_lock);
-
-       return ret;
-}
-
-static int power_ctrl(struct v4l2_subdev *sd, bool flag)
-{
-       int ret = 0;
-       struct ov2680_device *dev = to_ov2680_sensor(sd);
-       if (!dev || !dev->platform_data)
-               return -ENODEV;
-
-       /* Non-gmin platforms use the legacy callback */
-       if (dev->platform_data->power_ctrl)
-               return dev->platform_data->power_ctrl(sd, flag);
-
-       if (flag) {
-               ret |= dev->platform_data->v1p8_ctrl(sd, 1);
-               ret |= dev->platform_data->v2p8_ctrl(sd, 1);
-               usleep_range(10000, 15000);
-       }
-
-       if (!flag || ret) {
-               ret |= dev->platform_data->v1p8_ctrl(sd, 0);
-               ret |= dev->platform_data->v2p8_ctrl(sd, 0);
-       }
-       return ret;
-}
-
-static int gpio_ctrl(struct v4l2_subdev *sd, bool flag)
-{
-       int ret;
-       struct ov2680_device *dev = to_ov2680_sensor(sd);
-
-       if (!dev || !dev->platform_data)
-               return -ENODEV;
-
-       /* Non-gmin platforms use the legacy callback */
-       if (dev->platform_data->gpio_ctrl)
-               return dev->platform_data->gpio_ctrl(sd, flag);
-
-       /* The OV2680 documents only one GPIO input (#XSHUTDN), but
-        * existing integrations often wire two (reset/power_down)
-        * because that is the way other sensors work.  There is no
-        * way to tell how it is wired internally, so existing
-        * firmwares expose both and we drive them symmetrically. */
-       if (flag) {
-               ret = dev->platform_data->gpio0_ctrl(sd, 1);
-               usleep_range(10000, 15000);
-               /* Ignore return from second gpio, it may not be there */
-               dev->platform_data->gpio1_ctrl(sd, 1);
-               usleep_range(10000, 15000);
-       } else {
-               dev->platform_data->gpio1_ctrl(sd, 0);
-               ret = dev->platform_data->gpio0_ctrl(sd, 0);
-       }
-       return ret;
-}
-
-static int power_up(struct v4l2_subdev *sd)
-{
-       struct ov2680_device *dev = to_ov2680_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret;
-
-       if (!dev->platform_data) {
-               dev_err(&client->dev,
-                       "no camera_sensor_platform_data");
-               return -ENODEV;
-       }
-
-       /* power control */
-       ret = power_ctrl(sd, 1);
-       if (ret)
-               goto fail_power;
-
-       /* according to DS, at least 5ms is needed between DOVDD and PWDN */
-       usleep_range(5000, 6000);
-
-       /* gpio ctrl */
-       ret = gpio_ctrl(sd, 1);
-       if (ret) {
-               ret = gpio_ctrl(sd, 1);
-               if (ret)
-                       goto fail_power;
-       }
-
-       /* flis clock control */
-       ret = dev->platform_data->flisclk_ctrl(sd, 1);
-       if (ret)
-               goto fail_clk;
-
-       /* according to DS, 20ms is needed between PWDN and i2c access */
-       msleep(20);
-
-       return 0;
-
-fail_clk:
-       gpio_ctrl(sd, 0);
-fail_power:
-       power_ctrl(sd, 0);
-       dev_err(&client->dev, "sensor power-up failed\n");
-
-       return ret;
-}
-
-static int power_down(struct v4l2_subdev *sd)
-{
-       struct ov2680_device *dev = to_ov2680_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret = 0;
-
-       h_flag = 0;
-       v_flag = 0;
-       if (!dev->platform_data) {
-               dev_err(&client->dev,
-                       "no camera_sensor_platform_data");
-               return -ENODEV;
-       }
-
-       ret = dev->platform_data->flisclk_ctrl(sd, 0);
-       if (ret)
-               dev_err(&client->dev, "flisclk failed\n");
-
-       /* gpio ctrl */
-       ret = gpio_ctrl(sd, 0);
-       if (ret) {
-               ret = gpio_ctrl(sd, 0);
-               if (ret)
-                       dev_err(&client->dev, "gpio failed 2\n");
-       }
-
-       /* power control */
-       ret = power_ctrl(sd, 0);
-       if (ret)
-               dev_err(&client->dev, "vprog failed.\n");
-
-       return ret;
-}
-
-static int ov2680_s_power(struct v4l2_subdev *sd, int on)
-{
-       int ret;
-
-       if (on == 0){
-               ret = power_down(sd);
-       } else {
-               ret = power_up(sd);
-               if (!ret)
-                       return ov2680_init(sd);
-       }
-       return ret;
-}
-
-/*
- * distance - calculate the distance
- * @res: resolution
- * @w: width
- * @h: height
- *
- * Get the gap between resolution and w/h.
- * res->width/height smaller than w/h wouldn't be considered.
- * Returns the value of gap or -1 if fail.
- */
-#define LARGEST_ALLOWED_RATIO_MISMATCH 600
-static int distance(struct ov2680_resolution *res, u32 w, u32 h)
-{
-       unsigned int w_ratio = (res->width << 13) / w;
-       unsigned int h_ratio;
-       int match;
-
-       if (h == 0)
-               return -1;
-       h_ratio = (res->height << 13) / h;
-       if (h_ratio == 0)
-               return -1;
-       match   = abs(((w_ratio << 13) / h_ratio) - ((int)8192));
-
-
-       if ((w_ratio < (int)8192) || (h_ratio < (int)8192)  ||
-               (match > LARGEST_ALLOWED_RATIO_MISMATCH))
-               return -1;
-
-       return w_ratio + h_ratio;
-}
-
-/* Return the nearest higher resolution index */
-static int nearest_resolution_index(int w, int h)
-{
-       int i;
-       int idx = -1;
-       int dist;
-       int min_dist = INT_MAX;
-       struct ov2680_resolution *tmp_res = NULL;
-
-       for (i = 0; i < N_RES; i++) {
-               tmp_res = &ov2680_res[i];
-               dist = distance(tmp_res, w, h);
-               if (dist == -1)
-                       continue;
-               if (dist < min_dist) {
-                       min_dist = dist;
-                       idx = i;
-               }
-       }
-
-       return idx;
-}
-
-static int get_resolution_index(int w, int h)
-{
-       int i;
-
-       for (i = 0; i < N_RES; i++) {
-               if (w != ov2680_res[i].width)
-                       continue;
-               if (h != ov2680_res[i].height)
-                       continue;
-
-               return i;
-       }
-
-       return -1;
-}
-
-static int ov2680_set_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
-                         struct v4l2_subdev_format *format)
-{
-       struct v4l2_mbus_framefmt *fmt = &format->format;
-       struct ov2680_device *dev = to_ov2680_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct camera_mipi_info *ov2680_info = NULL;
-       int ret = 0;
-       int idx = 0;
-       dev_dbg(&client->dev, "+++++ov2680_s_mbus_fmt+++++l\n");
-       if (format->pad)
-               return -EINVAL;
-
-       if (!fmt)
-               return -EINVAL;
-
-       ov2680_info = v4l2_get_subdev_hostdata(sd);
-       if (!ov2680_info)
-               return -EINVAL;
-
-       mutex_lock(&dev->input_lock);
-       idx = nearest_resolution_index(fmt->width, fmt->height);
-       if (idx == -1) {
-               /* return the largest resolution */
-               fmt->width = ov2680_res[N_RES - 1].width;
-               fmt->height = ov2680_res[N_RES - 1].height;
-       } else {
-               fmt->width = ov2680_res[idx].width;
-               fmt->height = ov2680_res[idx].height;
-       }
-       fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
-       if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
-               cfg->try_fmt = *fmt;
-               mutex_unlock(&dev->input_lock);
-               return 0;
-               }
-       dev->fmt_idx = get_resolution_index(fmt->width, fmt->height);
-       dev_dbg(&client->dev, "+++++get_resolution_index=%d+++++l\n",
-                    dev->fmt_idx);
-       if (dev->fmt_idx == -1) {
-               dev_err(&client->dev, "get resolution fail\n");
-               mutex_unlock(&dev->input_lock);
-               return -EINVAL;
-       }
-       v4l2_info(client, "__s_mbus_fmt i=%d, w=%d, h=%d\n", dev->fmt_idx,
-                 fmt->width, fmt->height);
-       dev_dbg(&client->dev, "__s_mbus_fmt i=%d, w=%d, h=%d\n",
-                    dev->fmt_idx, fmt->width, fmt->height);
-
-       ret = ov2680_write_reg_array(client, ov2680_res[dev->fmt_idx].regs);
-       if (ret)
-               dev_err(&client->dev, "ov2680 write resolution register err\n");
-
-       ret = ov2680_get_intg_factor(client, ov2680_info,
-                                    &ov2680_res[dev->fmt_idx]);
-       if (ret) {
-               dev_err(&client->dev, "failed to get integration_factor\n");
-               goto err;
-       }
-
-       /*recall flip functions to avoid flip registers
-        * were overridden by default setting
-        */
-       if (h_flag)
-               ov2680_h_flip(sd, h_flag);
-       if (v_flag)
-               ov2680_v_flip(sd, v_flag);
-
-       v4l2_info(client, "\n%s idx %d \n", __func__, dev->fmt_idx);
-
-       /*ret = startup(sd);
-        * if (ret)
-        * dev_err(&client->dev, "ov2680 startup err\n");
-        */
-err:
-       mutex_unlock(&dev->input_lock);
-       return ret;
-}
-
-static int ov2680_get_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
-                         struct v4l2_subdev_format *format)
-{
-       struct v4l2_mbus_framefmt *fmt = &format->format;
-       struct ov2680_device *dev = to_ov2680_sensor(sd);
-
-       if (format->pad)
-               return -EINVAL;
-
-       if (!fmt)
-               return -EINVAL;
-
-       fmt->width = ov2680_res[dev->fmt_idx].width;
-       fmt->height = ov2680_res[dev->fmt_idx].height;
-       fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
-
-       return 0;
-}
-
-static int ov2680_detect(struct i2c_client *client)
-{
-       struct i2c_adapter *adapter = client->adapter;
-       u16 high, low;
-       int ret;
-       u16 id;
-       u8 revision;
-
-       if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
-               return -ENODEV;
-
-       ret = ov2680_read_reg(client, OV2680_8BIT,
-                                       OV2680_SC_CMMN_CHIP_ID_H, &high);
-       if (ret) {
-               dev_err(&client->dev, "sensor_id_high = 0x%x\n", high);
-               return -ENODEV;
-       }
-       ret = ov2680_read_reg(client, OV2680_8BIT,
-                                       OV2680_SC_CMMN_CHIP_ID_L, &low);
-       id = ((((u16) high) << 8) | (u16) low);
-
-       if (id != OV2680_ID) {
-               dev_err(&client->dev, "sensor ID error 0x%x\n", id);
-               return -ENODEV;
-       }
-
-       ret = ov2680_read_reg(client, OV2680_8BIT,
-                                       OV2680_SC_CMMN_SUB_ID, &high);
-       revision = (u8) high & 0x0f;
-
-       dev_info(&client->dev, "sensor_revision id = 0x%x\n", id);
-
-       return 0;
-}
-
-static int ov2680_s_stream(struct v4l2_subdev *sd, int enable)
-{
-       struct ov2680_device *dev = to_ov2680_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret;
-
-       mutex_lock(&dev->input_lock);
-       if(enable )
-               dev_dbg(&client->dev, "ov2680_s_stream one \n");
-       else
-               dev_dbg(&client->dev, "ov2680_s_stream off \n");
-
-       ret = ov2680_write_reg(client, OV2680_8BIT, OV2680_SW_STREAM,
-                               enable ? OV2680_START_STREAMING :
-                               OV2680_STOP_STREAMING);
-#if 0
-       /* restore settings */
-       ov2680_res = ov2680_res_preview;
-       N_RES = N_RES_PREVIEW;
-#endif
-
-       //otp valid at stream on state
-       //if(!dev->otp_data)
-       //      dev->otp_data = ov2680_otp_read(sd);
-
-       mutex_unlock(&dev->input_lock);
-
-       return ret;
-}
-
-
-static int ov2680_s_config(struct v4l2_subdev *sd,
-                          int irq, void *platform_data)
-{
-       struct ov2680_device *dev = to_ov2680_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret = 0;
-
-       if (!platform_data)
-               return -ENODEV;
-
-       dev->platform_data =
-               (struct camera_sensor_platform_data *)platform_data;
-
-       mutex_lock(&dev->input_lock);
-       /* power off the module, then power on it in future
-        * as first power on by board may not fulfill the
-        * power on sequqence needed by the module
-        */
-       ret = power_down(sd);
-       if (ret) {
-               dev_err(&client->dev, "ov2680 power-off err.\n");
-               goto fail_power_off;
-       }
-
-       ret = power_up(sd);
-       if (ret) {
-               dev_err(&client->dev, "ov2680 power-up err.\n");
-               goto fail_power_on;
-       }
-
-       ret = dev->platform_data->csi_cfg(sd, 1);
-       if (ret)
-               goto fail_csi_cfg;
-
-       /* config & detect sensor */
-       ret = ov2680_detect(client);
-       if (ret) {
-               dev_err(&client->dev, "ov2680_detect err s_config.\n");
-               goto fail_csi_cfg;
-       }
-
-       /* turn off sensor, after probed */
-       ret = power_down(sd);
-       if (ret) {
-               dev_err(&client->dev, "ov2680 power-off err.\n");
-               goto fail_csi_cfg;
-       }
-       mutex_unlock(&dev->input_lock);
-
-       return 0;
-
-fail_csi_cfg:
-       dev->platform_data->csi_cfg(sd, 0);
-fail_power_on:
-       power_down(sd);
-       dev_err(&client->dev, "sensor power-gating failed\n");
-fail_power_off:
-       mutex_unlock(&dev->input_lock);
-       return ret;
-}
-
-static int ov2680_g_parm(struct v4l2_subdev *sd,
-                       struct v4l2_streamparm *param)
-{
-       struct ov2680_device *dev = to_ov2680_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (!param)
-               return -EINVAL;
-
-       if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-               dev_err(&client->dev,  "unsupported buffer type.\n");
-               return -EINVAL;
-       }
-
-       memset(param, 0, sizeof(*param));
-       param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-       if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) {
-               param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
-               param->parm.capture.timeperframe.numerator = 1;
-               param->parm.capture.capturemode = dev->run_mode;
-               param->parm.capture.timeperframe.denominator =
-                       ov2680_res[dev->fmt_idx].fps;
-       }
-       return 0;
-}
-
-static int ov2680_s_parm(struct v4l2_subdev *sd,
-                       struct v4l2_streamparm *param)
-{
-       struct ov2680_device *dev = to_ov2680_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       dev->run_mode = param->parm.capture.capturemode;
-
-       v4l2_info(client, "\n%s:run_mode :%x\n", __func__, dev->run_mode);
-
-       mutex_lock(&dev->input_lock);
-       switch (dev->run_mode) {
-       case CI_MODE_VIDEO:
-               ov2680_res = ov2680_res_video;
-               N_RES = N_RES_VIDEO;
-               break;
-       case CI_MODE_STILL_CAPTURE:
-               ov2680_res = ov2680_res_still;
-               N_RES = N_RES_STILL;
-               break;
-       default:
-               ov2680_res = ov2680_res_preview;
-               N_RES = N_RES_PREVIEW;
-       }
-       mutex_unlock(&dev->input_lock);
-       return 0;
-}
-
-static int ov2680_g_frame_interval(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_frame_interval *interval)
-{
-       struct ov2680_device *dev = to_ov2680_sensor(sd);
-
-       interval->interval.numerator = 1;
-       interval->interval.denominator = ov2680_res[dev->fmt_idx].fps;
-
-       return 0;
-}
-
-static int ov2680_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
-                                struct v4l2_subdev_mbus_code_enum *code)
-{
-       if (code->index >= MAX_FMTS)
-               return -EINVAL;
-
-       code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
-       return 0;
-}
-
-static int ov2680_enum_frame_size(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
-                                 struct v4l2_subdev_frame_size_enum *fse)
-{
-       int index = fse->index;
-
-       if (index >= N_RES)
-               return -EINVAL;
-
-       fse->min_width = ov2680_res[index].width;
-       fse->min_height = ov2680_res[index].height;
-       fse->max_width = ov2680_res[index].width;
-       fse->max_height = ov2680_res[index].height;
-
-       return 0;
-
-}
-
-static int ov2680_g_skip_frames(struct v4l2_subdev *sd, u32 *frames)
-{
-       struct ov2680_device *dev = to_ov2680_sensor(sd);
-
-       mutex_lock(&dev->input_lock);
-       *frames = ov2680_res[dev->fmt_idx].skip_frames;
-       mutex_unlock(&dev->input_lock);
-
-       return 0;
-}
-
-static const struct v4l2_subdev_video_ops ov2680_video_ops = {
-       .s_stream = ov2680_s_stream,
-       .g_parm = ov2680_g_parm,
-       .s_parm = ov2680_s_parm,
-       .g_frame_interval = ov2680_g_frame_interval,
-};
-
-static const struct v4l2_subdev_sensor_ops ov2680_sensor_ops = {
-               .g_skip_frames  = ov2680_g_skip_frames,
-};
-
-static const struct v4l2_subdev_core_ops ov2680_core_ops = {
-       .s_power = ov2680_s_power,
-       .ioctl = ov2680_ioctl,
-};
-
-static const struct v4l2_subdev_pad_ops ov2680_pad_ops = {
-       .enum_mbus_code = ov2680_enum_mbus_code,
-       .enum_frame_size = ov2680_enum_frame_size,
-       .get_fmt = ov2680_get_fmt,
-       .set_fmt = ov2680_set_fmt,
-};
-
-static const struct v4l2_subdev_ops ov2680_ops = {
-       .core = &ov2680_core_ops,
-       .video = &ov2680_video_ops,
-       .pad = &ov2680_pad_ops,
-       .sensor = &ov2680_sensor_ops,
-};
-
-static int ov2680_remove(struct i2c_client *client)
-{
-       struct v4l2_subdev *sd = i2c_get_clientdata(client);
-       struct ov2680_device *dev = to_ov2680_sensor(sd);
-       dev_dbg(&client->dev, "ov2680_remove...\n");
-
-       dev->platform_data->csi_cfg(sd, 0);
-
-       v4l2_device_unregister_subdev(sd);
-       media_entity_cleanup(&dev->sd.entity);
-       v4l2_ctrl_handler_free(&dev->ctrl_handler);
-       kfree(dev);
-
-       return 0;
-}
-
-static int ov2680_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
-{
-       struct ov2680_device *dev;
-       int ret;
-       void *pdata;
-       unsigned int i;
-
-       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-       if (!dev) {
-               dev_err(&client->dev, "out of memory\n");
-               return -ENOMEM;
-       }
-
-       mutex_init(&dev->input_lock);
-
-       dev->fmt_idx = 0;
-       v4l2_i2c_subdev_init(&(dev->sd), client, &ov2680_ops);
-
-       if (ACPI_COMPANION(&client->dev))
-               pdata = gmin_camera_platform_data(&dev->sd,
-                                                 ATOMISP_INPUT_FORMAT_RAW_10,
-                                                 atomisp_bayer_order_bggr);
-       else
-               pdata = client->dev.platform_data;
-
-       if (!pdata) {
-               ret = -EINVAL;
-               goto out_free;
-        }
-
-       ret = ov2680_s_config(&dev->sd, client->irq, pdata);
-       if (ret)
-               goto out_free;
-
-       ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA);
-       if (ret)
-               goto out_free;
-
-       dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-       dev->pad.flags = MEDIA_PAD_FL_SOURCE;
-       dev->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
-       dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
-       ret =
-           v4l2_ctrl_handler_init(&dev->ctrl_handler,
-                                  ARRAY_SIZE(ov2680_controls));
-       if (ret) {
-               ov2680_remove(client);
-               return ret;
-       }
-
-       for (i = 0; i < ARRAY_SIZE(ov2680_controls); i++)
-               v4l2_ctrl_new_custom(&dev->ctrl_handler, &ov2680_controls[i],
-                                    NULL);
-
-       if (dev->ctrl_handler.error) {
-               ov2680_remove(client);
-               return dev->ctrl_handler.error;
-       }
-
-       /* Use same lock for controls as for everything else. */
-       dev->ctrl_handler.lock = &dev->input_lock;
-       dev->sd.ctrl_handler = &dev->ctrl_handler;
-
-       ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad);
-       if (ret)
-       {
-               ov2680_remove(client);
-               dev_dbg(&client->dev, "+++ remove ov2680 \n");
-       }
-       return ret;
-out_free:
-       dev_dbg(&client->dev, "+++ out free \n");
-       v4l2_device_unregister_subdev(&dev->sd);
-       kfree(dev);
-       return ret;
-}
-
-static const struct acpi_device_id ov2680_acpi_match[] = {
-       {"XXOV2680"},
-       {"OVTI2680"},
-       {},
-};
-MODULE_DEVICE_TABLE(acpi, ov2680_acpi_match);
-
-
-MODULE_DEVICE_TABLE(i2c, ov2680_id);
-static struct i2c_driver ov2680_driver = {
-       .driver = {
-               .owner = THIS_MODULE,
-               .name = OV2680_NAME,
-               .acpi_match_table = ACPI_PTR(ov2680_acpi_match),
-
-       },
-       .probe = ov2680_probe,
-       .remove = ov2680_remove,
-       .id_table = ov2680_id,
-};
-
-static int init_ov2680(void)
-{
-       return i2c_add_driver(&ov2680_driver);
-}
-
-static void exit_ov2680(void)
-{
-
-       i2c_del_driver(&ov2680_driver);
-}
-
-module_init(init_ov2680);
-module_exit(exit_ov2680);
-
-MODULE_AUTHOR("Jacky Wang <Jacky_wang@ovt.com>");
-MODULE_DESCRIPTION("A low-level driver for OmniVision 2680 sensors");
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/staging/media/atomisp/i2c/ov2722.c b/drivers/staging/media/atomisp/i2c/ov2722.c
deleted file mode 100644 (file)
index 10094ac..0000000
+++ /dev/null
@@ -1,1373 +0,0 @@
-/*
- * Support for OmniVision OV2722 1080p HD camera sensor.
- *
- * Copyright (c) 2013 Intel Corporation. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/kmod.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/gpio.h>
-#include <linux/moduleparam.h>
-#include <media/v4l2-device.h>
-#include "../include/linux/atomisp_gmin_platform.h"
-#include <linux/acpi.h>
-#include <linux/io.h>
-
-#include "ov2722.h"
-
-/* i2c read/write stuff */
-static int ov2722_read_reg(struct i2c_client *client,
-                          u16 data_length, u16 reg, u16 *val)
-{
-       int err;
-       struct i2c_msg msg[2];
-       unsigned char data[6];
-
-       if (!client->adapter) {
-               dev_err(&client->dev, "%s error, no client->adapter\n",
-                       __func__);
-               return -ENODEV;
-       }
-
-       if (data_length != OV2722_8BIT && data_length != OV2722_16BIT
-                                       && data_length != OV2722_32BIT) {
-               dev_err(&client->dev, "%s error, invalid data length\n",
-                       __func__);
-               return -EINVAL;
-       }
-
-       memset(msg, 0 , sizeof(msg));
-
-       msg[0].addr = client->addr;
-       msg[0].flags = 0;
-       msg[0].len = I2C_MSG_LENGTH;
-       msg[0].buf = data;
-
-       /* high byte goes out first */
-       data[0] = (u8)(reg >> 8);
-       data[1] = (u8)(reg & 0xff);
-
-       msg[1].addr = client->addr;
-       msg[1].len = data_length;
-       msg[1].flags = I2C_M_RD;
-       msg[1].buf = data;
-
-       err = i2c_transfer(client->adapter, msg, 2);
-       if (err != 2) {
-               if (err >= 0)
-                       err = -EIO;
-               dev_err(&client->dev,
-                       "read from offset 0x%x error %d", reg, err);
-               return err;
-       }
-
-       *val = 0;
-       /* high byte comes first */
-       if (data_length == OV2722_8BIT)
-               *val = (u8)data[0];
-       else if (data_length == OV2722_16BIT)
-               *val = be16_to_cpu(*(u16 *)&data[0]);
-       else
-               *val = be32_to_cpu(*(u32 *)&data[0]);
-
-       return 0;
-}
-
-static int ov2722_i2c_write(struct i2c_client *client, u16 len, u8 *data)
-{
-       struct i2c_msg msg;
-       const int num_msg = 1;
-       int ret;
-
-       msg.addr = client->addr;
-       msg.flags = 0;
-       msg.len = len;
-       msg.buf = data;
-       ret = i2c_transfer(client->adapter, &msg, 1);
-
-       return ret == num_msg ? 0 : -EIO;
-}
-
-static int ov2722_write_reg(struct i2c_client *client, u16 data_length,
-                                                       u16 reg, u16 val)
-{
-       int ret;
-       unsigned char data[4] = {0};
-       u16 *wreg = (u16 *)data;
-       const u16 len = data_length + sizeof(u16); /* 16-bit address + data */
-
-       if (data_length != OV2722_8BIT && data_length != OV2722_16BIT) {
-               dev_err(&client->dev,
-                       "%s error, invalid data_length\n", __func__);
-               return -EINVAL;
-       }
-
-       /* high byte goes out first */
-       *wreg = cpu_to_be16(reg);
-
-       if (data_length == OV2722_8BIT) {
-               data[2] = (u8)(val);
-       } else {
-               /* OV2722_16BIT */
-               u16 *wdata = (u16 *)&data[2];
-               *wdata = cpu_to_be16(val);
-       }
-
-       ret = ov2722_i2c_write(client, len, data);
-       if (ret)
-               dev_err(&client->dev,
-                       "write error: wrote 0x%x to offset 0x%x error %d",
-                       val, reg, ret);
-
-       return ret;
-}
-
-/*
- * ov2722_write_reg_array - Initializes a list of OV2722 registers
- * @client: i2c driver client structure
- * @reglist: list of registers to be written
- *
- * This function initializes a list of registers. When consecutive addresses
- * are found in a row on the list, this function creates a buffer and sends
- * consecutive data in a single i2c_transfer().
- *
- * __ov2722_flush_reg_array, __ov2722_buf_reg_array() and
- * __ov2722_write_reg_is_consecutive() are internal functions to
- * ov2722_write_reg_array_fast() and should be not used anywhere else.
- *
- */
-
-static int __ov2722_flush_reg_array(struct i2c_client *client,
-                                   struct ov2722_write_ctrl *ctrl)
-{
-       u16 size;
-
-       if (ctrl->index == 0)
-               return 0;
-
-       size = sizeof(u16) + ctrl->index; /* 16-bit address + data */
-       ctrl->buffer.addr = cpu_to_be16(ctrl->buffer.addr);
-       ctrl->index = 0;
-
-       return ov2722_i2c_write(client, size, (u8 *)&ctrl->buffer);
-}
-
-static int __ov2722_buf_reg_array(struct i2c_client *client,
-                                 struct ov2722_write_ctrl *ctrl,
-                                 const struct ov2722_reg *next)
-{
-       int size;
-       u16 *data16;
-
-       switch (next->type) {
-       case OV2722_8BIT:
-               size = 1;
-               ctrl->buffer.data[ctrl->index] = (u8)next->val;
-               break;
-       case OV2722_16BIT:
-               size = 2;
-               data16 = (u16 *)&ctrl->buffer.data[ctrl->index];
-               *data16 = cpu_to_be16((u16)next->val);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       /* When first item is added, we need to store its starting address */
-       if (ctrl->index == 0)
-               ctrl->buffer.addr = next->reg;
-
-       ctrl->index += size;
-
-       /*
-        * Buffer cannot guarantee free space for u32? Better flush it to avoid
-        * possible lack of memory for next item.
-        */
-       if (ctrl->index + sizeof(u16) >= OV2722_MAX_WRITE_BUF_SIZE)
-               return __ov2722_flush_reg_array(client, ctrl);
-
-       return 0;
-}
-
-static int __ov2722_write_reg_is_consecutive(struct i2c_client *client,
-                                            struct ov2722_write_ctrl *ctrl,
-                                            const struct ov2722_reg *next)
-{
-       if (ctrl->index == 0)
-               return 1;
-
-       return ctrl->buffer.addr + ctrl->index == next->reg;
-}
-
-static int ov2722_write_reg_array(struct i2c_client *client,
-                                 const struct ov2722_reg *reglist)
-{
-       const struct ov2722_reg *next = reglist;
-       struct ov2722_write_ctrl ctrl;
-       int err;
-
-       ctrl.index = 0;
-       for (; next->type != OV2722_TOK_TERM; next++) {
-               switch (next->type & OV2722_TOK_MASK) {
-               case OV2722_TOK_DELAY:
-                       err = __ov2722_flush_reg_array(client, &ctrl);
-                       if (err)
-                               return err;
-                       msleep(next->val);
-                       break;
-               default:
-                       /*
-                        * If next address is not consecutive, data needs to be
-                        * flushed before proceed.
-                        */
-                       if (!__ov2722_write_reg_is_consecutive(client, &ctrl,
-                                                               next)) {
-                               err = __ov2722_flush_reg_array(client, &ctrl);
-                               if (err)
-                                       return err;
-                       }
-                       err = __ov2722_buf_reg_array(client, &ctrl, next);
-                       if (err) {
-                               dev_err(&client->dev, "%s: write error, aborted\n",
-                                        __func__);
-                               return err;
-                       }
-                       break;
-               }
-       }
-
-       return __ov2722_flush_reg_array(client, &ctrl);
-}
-static int ov2722_g_focal(struct v4l2_subdev *sd, s32 *val)
-{
-       *val = (OV2722_FOCAL_LENGTH_NUM << 16) | OV2722_FOCAL_LENGTH_DEM;
-       return 0;
-}
-
-static int ov2722_g_fnumber(struct v4l2_subdev *sd, s32 *val)
-{
-       /*const f number for imx*/
-       *val = (OV2722_F_NUMBER_DEFAULT_NUM << 16) | OV2722_F_NUMBER_DEM;
-       return 0;
-}
-
-static int ov2722_g_fnumber_range(struct v4l2_subdev *sd, s32 *val)
-{
-       *val = (OV2722_F_NUMBER_DEFAULT_NUM << 24) |
-               (OV2722_F_NUMBER_DEM << 16) |
-               (OV2722_F_NUMBER_DEFAULT_NUM << 8) | OV2722_F_NUMBER_DEM;
-       return 0;
-}
-
-static int ov2722_get_intg_factor(struct i2c_client *client,
-                               struct camera_mipi_info *info,
-                               const struct ov2722_resolution *res)
-{
-       struct v4l2_subdev *sd = i2c_get_clientdata(client);
-       struct ov2722_device *dev = NULL;
-       struct atomisp_sensor_mode_data *buf = &info->data;
-       const unsigned int ext_clk_freq_hz = 19200000;
-       const unsigned int pll_invariant_div = 10;
-       unsigned int pix_clk_freq_hz;
-       u16 pre_pll_clk_div;
-       u16 pll_multiplier;
-       u16 op_pix_clk_div;
-       u16 reg_val;
-       int ret;
-
-       if (!info)
-               return -EINVAL;
-
-       dev = to_ov2722_sensor(sd);
-
-       /* pixel clock calculattion */
-       ret =  ov2722_read_reg(client, OV2722_8BIT,
-                               OV2722_SC_CMMN_PLL_CTRL3, &pre_pll_clk_div);
-       if (ret)
-               return ret;
-
-       ret =  ov2722_read_reg(client, OV2722_8BIT,
-                               OV2722_SC_CMMN_PLL_MULTIPLIER, &pll_multiplier);
-       if (ret)
-               return ret;
-
-       ret =  ov2722_read_reg(client, OV2722_8BIT,
-                               OV2722_SC_CMMN_PLL_DEBUG_OPT, &op_pix_clk_div);
-       if (ret)
-               return ret;
-
-       pre_pll_clk_div = (pre_pll_clk_div & 0x70) >> 4;
-       if (0 == pre_pll_clk_div)
-               return -EINVAL;
-
-       pll_multiplier = pll_multiplier & 0x7f;
-       op_pix_clk_div = op_pix_clk_div & 0x03;
-       pix_clk_freq_hz = ext_clk_freq_hz / pre_pll_clk_div * pll_multiplier
-                               * op_pix_clk_div / pll_invariant_div;
-
-       dev->vt_pix_clk_freq_mhz = pix_clk_freq_hz;
-       buf->vt_pix_clk_freq_mhz = pix_clk_freq_hz;
-
-       /* get integration time */
-       buf->coarse_integration_time_min = OV2722_COARSE_INTG_TIME_MIN;
-       buf->coarse_integration_time_max_margin =
-                                       OV2722_COARSE_INTG_TIME_MAX_MARGIN;
-
-       buf->fine_integration_time_min = OV2722_FINE_INTG_TIME_MIN;
-       buf->fine_integration_time_max_margin =
-                                       OV2722_FINE_INTG_TIME_MAX_MARGIN;
-
-       buf->fine_integration_time_def = OV2722_FINE_INTG_TIME_MIN;
-       buf->frame_length_lines = res->lines_per_frame;
-       buf->line_length_pck = res->pixels_per_line;
-       buf->read_mode = res->bin_mode;
-
-       /* get the cropping and output resolution to ISP for this mode. */
-       ret =  ov2722_read_reg(client, OV2722_16BIT,
-                                       OV2722_H_CROP_START_H, &reg_val);
-       if (ret)
-               return ret;
-       buf->crop_horizontal_start = reg_val;
-
-       ret =  ov2722_read_reg(client, OV2722_16BIT,
-                                       OV2722_V_CROP_START_H, &reg_val);
-       if (ret)
-               return ret;
-       buf->crop_vertical_start = reg_val;
-
-       ret = ov2722_read_reg(client, OV2722_16BIT,
-                                       OV2722_H_CROP_END_H, &reg_val);
-       if (ret)
-               return ret;
-       buf->crop_horizontal_end = reg_val;
-
-       ret = ov2722_read_reg(client, OV2722_16BIT,
-                                       OV2722_V_CROP_END_H, &reg_val);
-       if (ret)
-               return ret;
-       buf->crop_vertical_end = reg_val;
-
-       ret = ov2722_read_reg(client, OV2722_16BIT,
-                                       OV2722_H_OUTSIZE_H, &reg_val);
-       if (ret)
-               return ret;
-       buf->output_width = reg_val;
-
-       ret = ov2722_read_reg(client, OV2722_16BIT,
-                                       OV2722_V_OUTSIZE_H, &reg_val);
-       if (ret)
-               return ret;
-       buf->output_height = reg_val;
-
-       buf->binning_factor_x = res->bin_factor_x ?
-                                       res->bin_factor_x : 1;
-       buf->binning_factor_y = res->bin_factor_y ?
-                                       res->bin_factor_y : 1;
-       return 0;
-}
-
-static long __ov2722_set_exposure(struct v4l2_subdev *sd, int coarse_itg,
-                                int gain, int digitgain)
-
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct ov2722_device *dev = to_ov2722_sensor(sd);
-       u16 hts, vts;
-       int ret;
-
-       dev_dbg(&client->dev, "set_exposure without group hold\n");
-
-       /* clear VTS_DIFF on manual mode */
-       ret = ov2722_write_reg(client, OV2722_16BIT, OV2722_VTS_DIFF_H, 0);
-       if (ret)
-               return ret;
-
-       hts = dev->pixels_per_line;
-       vts = dev->lines_per_frame;
-
-       if ((coarse_itg + OV2722_COARSE_INTG_TIME_MAX_MARGIN) > vts)
-               vts = coarse_itg + OV2722_COARSE_INTG_TIME_MAX_MARGIN;
-
-       coarse_itg <<= 4;
-       digitgain <<= 2;
-
-       ret = ov2722_write_reg(client, OV2722_16BIT,
-                               OV2722_VTS_H, vts);
-       if (ret)
-               return ret;
-
-       ret = ov2722_write_reg(client, OV2722_16BIT,
-                               OV2722_HTS_H, hts);
-       if (ret)
-               return ret;
-
-       /* set exposure */
-       ret = ov2722_write_reg(client, OV2722_8BIT,
-                                       OV2722_AEC_PK_EXPO_L,
-                                       coarse_itg & 0xff);
-       if (ret)
-               return ret;
-
-       ret = ov2722_write_reg(client, OV2722_16BIT,
-                                       OV2722_AEC_PK_EXPO_H,
-                                       (coarse_itg >> 8) & 0xfff);
-       if (ret)
-               return ret;
-
-       /* set analog gain */
-       ret = ov2722_write_reg(client, OV2722_16BIT,
-                                       OV2722_AGC_ADJ_H, gain);
-       if (ret)
-               return ret;
-
-       /* set digital gain */
-       ret = ov2722_write_reg(client, OV2722_16BIT,
-                               OV2722_MWB_GAIN_R_H, digitgain);
-       if (ret)
-               return ret;
-
-       ret = ov2722_write_reg(client, OV2722_16BIT,
-                               OV2722_MWB_GAIN_G_H, digitgain);
-       if (ret)
-               return ret;
-
-       ret = ov2722_write_reg(client, OV2722_16BIT,
-                               OV2722_MWB_GAIN_B_H, digitgain);
-
-       return ret;
-}
-
-static int ov2722_set_exposure(struct v4l2_subdev *sd, int exposure,
-       int gain, int digitgain)
-{
-       struct ov2722_device *dev = to_ov2722_sensor(sd);
-       int ret;
-
-       mutex_lock(&dev->input_lock);
-       ret = __ov2722_set_exposure(sd, exposure, gain, digitgain);
-       mutex_unlock(&dev->input_lock);
-
-       return ret;
-}
-
-static long ov2722_s_exposure(struct v4l2_subdev *sd,
-                              struct atomisp_exposure *exposure)
-{
-       int exp = exposure->integration_time[0];
-       int gain = exposure->gain[0];
-       int digitgain = exposure->gain[1];
-
-       /* we should not accept the invalid value below. */
-       if (gain == 0) {
-               struct i2c_client *client = v4l2_get_subdevdata(sd);
-               v4l2_err(client, "%s: invalid value\n", __func__);
-               return -EINVAL;
-       }
-
-       return ov2722_set_exposure(sd, exp, gain, digitgain);
-}
-
-static long ov2722_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
-{
-
-       switch (cmd) {
-       case ATOMISP_IOC_S_EXPOSURE:
-               return ov2722_s_exposure(sd, arg);
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-
-/* This returns the exposure time being used. This should only be used
- * for filling in EXIF data, not for actual image processing.
- */
-static int ov2722_q_exposure(struct v4l2_subdev *sd, s32 *value)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       u16 reg_v, reg_v2;
-       int ret;
-
-       /* get exposure */
-       ret = ov2722_read_reg(client, OV2722_8BIT,
-                                       OV2722_AEC_PK_EXPO_L,
-                                       &reg_v);
-       if (ret)
-               goto err;
-
-       ret = ov2722_read_reg(client, OV2722_8BIT,
-                                       OV2722_AEC_PK_EXPO_M,
-                                       &reg_v2);
-       if (ret)
-               goto err;
-
-       reg_v += reg_v2 << 8;
-       ret = ov2722_read_reg(client, OV2722_8BIT,
-                                       OV2722_AEC_PK_EXPO_H,
-                                       &reg_v2);
-       if (ret)
-               goto err;
-
-       *value = reg_v + (((u32)reg_v2 << 16));
-err:
-       return ret;
-}
-
-static int ov2722_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
-{
-       struct ov2722_device *dev =
-           container_of(ctrl->handler, struct ov2722_device, ctrl_handler);
-       int ret = 0;
-       unsigned int val;
-       switch (ctrl->id) {
-       case V4L2_CID_EXPOSURE_ABSOLUTE:
-               ret = ov2722_q_exposure(&dev->sd, &ctrl->val);
-               break;
-       case V4L2_CID_FOCAL_ABSOLUTE:
-               ret = ov2722_g_focal(&dev->sd, &ctrl->val);
-               break;
-       case V4L2_CID_FNUMBER_ABSOLUTE:
-               ret = ov2722_g_fnumber(&dev->sd, &ctrl->val);
-               break;
-       case V4L2_CID_FNUMBER_RANGE:
-               ret = ov2722_g_fnumber_range(&dev->sd, &ctrl->val);
-               break;
-       case V4L2_CID_LINK_FREQ:
-               val = ov2722_res[dev->fmt_idx].mipi_freq;
-               if (val == 0)
-                       return -EINVAL;
-
-               ctrl->val = val * 1000; /* To Hz */
-               break;
-       default:
-               ret = -EINVAL;
-       }
-
-       return ret;
-}
-
-static const struct v4l2_ctrl_ops ctrl_ops = {
-       .g_volatile_ctrl = ov2722_g_volatile_ctrl
-};
-
-struct v4l2_ctrl_config ov2722_controls[] = {
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_EXPOSURE_ABSOLUTE,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .name = "exposure",
-        .min = 0x0,
-        .max = 0xffff,
-        .step = 0x01,
-        .def = 0x00,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_FOCAL_ABSOLUTE,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .name = "focal length",
-        .min = OV2722_FOCAL_LENGTH_DEFAULT,
-        .max = OV2722_FOCAL_LENGTH_DEFAULT,
-        .step = 0x01,
-        .def = OV2722_FOCAL_LENGTH_DEFAULT,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_FNUMBER_ABSOLUTE,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .name = "f-number",
-        .min = OV2722_F_NUMBER_DEFAULT,
-        .max = OV2722_F_NUMBER_DEFAULT,
-        .step = 0x01,
-        .def = OV2722_F_NUMBER_DEFAULT,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_FNUMBER_RANGE,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .name = "f-number range",
-        .min = OV2722_F_NUMBER_RANGE,
-        .max = OV2722_F_NUMBER_RANGE,
-        .step = 0x01,
-        .def = OV2722_F_NUMBER_RANGE,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_LINK_FREQ,
-        .name = "Link Frequency",
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .min = 1,
-        .max = 1500000 * 1000,
-        .step = 1,
-        .def = 1,
-        .flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
-        },
-};
-
-static int ov2722_init(struct v4l2_subdev *sd)
-{
-       struct ov2722_device *dev = to_ov2722_sensor(sd);
-
-       mutex_lock(&dev->input_lock);
-
-       /* restore settings */
-       ov2722_res = ov2722_res_preview;
-       N_RES = N_RES_PREVIEW;
-
-       mutex_unlock(&dev->input_lock);
-
-       return 0;
-}
-
-static int power_ctrl(struct v4l2_subdev *sd, bool flag)
-{
-       int ret = -1;
-       struct ov2722_device *dev = to_ov2722_sensor(sd);
-
-       if (!dev || !dev->platform_data)
-               return -ENODEV;
-
-       /* Non-gmin platforms use the legacy callback */
-       if (dev->platform_data->power_ctrl)
-               return dev->platform_data->power_ctrl(sd, flag);
-
-       if (flag) {
-               ret = dev->platform_data->v1p8_ctrl(sd, 1);
-               if (ret == 0) {
-                       ret = dev->platform_data->v2p8_ctrl(sd, 1);
-                       if (ret)
-                               dev->platform_data->v1p8_ctrl(sd, 0);
-               }
-       } else {
-               ret = dev->platform_data->v1p8_ctrl(sd, 0);
-               ret |= dev->platform_data->v2p8_ctrl(sd, 0);
-       }
-
-       return ret;
-}
-
-static int gpio_ctrl(struct v4l2_subdev *sd, bool flag)
-{
-       struct ov2722_device *dev = to_ov2722_sensor(sd);
-       int ret = -1;
-
-       if (!dev || !dev->platform_data)
-               return -ENODEV;
-
-       /* Non-gmin platforms use the legacy callback */
-       if (dev->platform_data->gpio_ctrl)
-               return dev->platform_data->gpio_ctrl(sd, flag);
-
-       /* Note: the GPIO order is asymmetric: always RESET#
-        * before PWDN# when turning it on or off.
-        */
-       ret = dev->platform_data->gpio0_ctrl(sd, flag);
-       /*
-        *ov2722 PWDN# active high when pull down,opposite to the convention
-        */
-       ret |= dev->platform_data->gpio1_ctrl(sd, !flag);
-       return ret;
-}
-
-static int power_up(struct v4l2_subdev *sd)
-{
-       struct ov2722_device *dev = to_ov2722_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret;
-
-       if (!dev->platform_data) {
-               dev_err(&client->dev,
-                       "no camera_sensor_platform_data");
-               return -ENODEV;
-       }
-
-       /* power control */
-       ret = power_ctrl(sd, 1);
-       if (ret)
-               goto fail_power;
-
-       /* according to DS, at least 5ms is needed between DOVDD and PWDN */
-       usleep_range(5000, 6000);
-
-       /* gpio ctrl */
-       ret = gpio_ctrl(sd, 1);
-       if (ret) {
-               ret = gpio_ctrl(sd, 0);
-               if (ret)
-                       goto fail_power;
-       }
-
-       /* flis clock control */
-       ret = dev->platform_data->flisclk_ctrl(sd, 1);
-       if (ret)
-               goto fail_clk;
-
-       /* according to DS, 20ms is needed between PWDN and i2c access */
-       msleep(20);
-
-       return 0;
-
-fail_clk:
-       gpio_ctrl(sd, 0);
-fail_power:
-       power_ctrl(sd, 0);
-       dev_err(&client->dev, "sensor power-up failed\n");
-
-       return ret;
-}
-
-static int power_down(struct v4l2_subdev *sd)
-{
-       struct ov2722_device *dev = to_ov2722_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret = 0;
-
-       if (!dev->platform_data) {
-               dev_err(&client->dev,
-                       "no camera_sensor_platform_data");
-               return -ENODEV;
-       }
-
-       ret = dev->platform_data->flisclk_ctrl(sd, 0);
-       if (ret)
-               dev_err(&client->dev, "flisclk failed\n");
-
-       /* gpio ctrl */
-       ret = gpio_ctrl(sd, 0);
-       if (ret) {
-               ret = gpio_ctrl(sd, 0);
-               if (ret)
-                       dev_err(&client->dev, "gpio failed 2\n");
-       }
-
-       /* power control */
-       ret = power_ctrl(sd, 0);
-       if (ret)
-               dev_err(&client->dev, "vprog failed.\n");
-
-       return ret;
-}
-
-static int ov2722_s_power(struct v4l2_subdev *sd, int on)
-{
-       int ret;
-       if (on == 0)
-               return power_down(sd);
-       else {
-               ret = power_up(sd);
-               if (!ret)
-                       return ov2722_init(sd);
-       }
-       return ret;
-}
-
-/*
- * distance - calculate the distance
- * @res: resolution
- * @w: width
- * @h: height
- *
- * Get the gap between resolution and w/h.
- * res->width/height smaller than w/h wouldn't be considered.
- * Returns the value of gap or -1 if fail.
- */
-#define LARGEST_ALLOWED_RATIO_MISMATCH 800
-static int distance(struct ov2722_resolution *res, u32 w, u32 h)
-{
-       unsigned int w_ratio = (res->width << 13) / w;
-       unsigned int h_ratio;
-       int match;
-
-       if (h == 0)
-               return -1;
-       h_ratio = (res->height << 13) / h;
-       if (h_ratio == 0)
-               return -1;
-       match   = abs(((w_ratio << 13) / h_ratio) - 8192);
-
-       if ((w_ratio < 8192) || (h_ratio < 8192) ||
-           (match > LARGEST_ALLOWED_RATIO_MISMATCH))
-               return -1;
-
-       return w_ratio + h_ratio;
-}
-
-/* Return the nearest higher resolution index */
-static int nearest_resolution_index(int w, int h)
-{
-       int i;
-       int idx = -1;
-       int dist;
-       int min_dist = INT_MAX;
-       struct ov2722_resolution *tmp_res = NULL;
-
-       for (i = 0; i < N_RES; i++) {
-               tmp_res = &ov2722_res[i];
-               dist = distance(tmp_res, w, h);
-               if (dist == -1)
-                       continue;
-               if (dist < min_dist) {
-                       min_dist = dist;
-                       idx = i;
-               }
-       }
-
-       return idx;
-}
-
-static int get_resolution_index(int w, int h)
-{
-       int i;
-
-       for (i = 0; i < N_RES; i++) {
-               if (w != ov2722_res[i].width)
-                       continue;
-               if (h != ov2722_res[i].height)
-                       continue;
-
-               return i;
-       }
-
-       return -1;
-}
-
-/* TODO: remove it. */
-static int startup(struct v4l2_subdev *sd)
-{
-       struct ov2722_device *dev = to_ov2722_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret = 0;
-
-       ret = ov2722_write_reg(client, OV2722_8BIT,
-                                       OV2722_SW_RESET, 0x01);
-       if (ret) {
-               dev_err(&client->dev, "ov2722 reset err.\n");
-               return ret;
-       }
-
-       ret = ov2722_write_reg_array(client, ov2722_res[dev->fmt_idx].regs);
-       if (ret) {
-               dev_err(&client->dev, "ov2722 write register err.\n");
-               return ret;
-       }
-
-       return ret;
-}
-
-static int ov2722_set_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
-                         struct v4l2_subdev_format *format)
-{
-       struct v4l2_mbus_framefmt *fmt = &format->format;
-       struct ov2722_device *dev = to_ov2722_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct camera_mipi_info *ov2722_info = NULL;
-       int ret = 0;
-       int idx;
-       if (format->pad)
-               return -EINVAL;
-       if (!fmt)
-               return -EINVAL;
-       ov2722_info = v4l2_get_subdev_hostdata(sd);
-       if (!ov2722_info)
-               return -EINVAL;
-
-       mutex_lock(&dev->input_lock);
-       idx = nearest_resolution_index(fmt->width, fmt->height);
-       if (idx == -1) {
-               /* return the largest resolution */
-               fmt->width = ov2722_res[N_RES - 1].width;
-               fmt->height = ov2722_res[N_RES - 1].height;
-       } else {
-               fmt->width = ov2722_res[idx].width;
-               fmt->height = ov2722_res[idx].height;
-       }
-       fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
-       if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
-               cfg->try_fmt = *fmt;
-               mutex_unlock(&dev->input_lock);
-               return 0;
-       }
-
-       dev->fmt_idx = get_resolution_index(fmt->width, fmt->height);
-       if (dev->fmt_idx == -1) {
-               dev_err(&client->dev, "get resolution fail\n");
-               mutex_unlock(&dev->input_lock);
-               return -EINVAL;
-       }
-
-       dev->pixels_per_line = ov2722_res[dev->fmt_idx].pixels_per_line;
-       dev->lines_per_frame = ov2722_res[dev->fmt_idx].lines_per_frame;
-
-       ret = startup(sd);
-       if (ret) {
-               int i = 0;
-               dev_err(&client->dev, "ov2722 startup err, retry to power up\n");
-               for (i = 0; i < OV2722_POWER_UP_RETRY_NUM; i++) {
-                       dev_err(&client->dev,
-                               "ov2722 retry to power up %d/%d times, result: ",
-                               i + 1, OV2722_POWER_UP_RETRY_NUM);
-                       power_down(sd);
-                       ret = power_up(sd);
-                       if (ret) {
-                               dev_err(&client->dev, "power up failed, continue\n");
-                               continue;
-                       }
-                       ret = startup(sd);
-                       if (ret) {
-                               dev_err(&client->dev, " startup FAILED!\n");
-                       } else {
-                               dev_err(&client->dev, " startup SUCCESS!\n");
-                               break;
-                       }
-               }
-               if (ret) {
-                       dev_err(&client->dev, "ov2722 startup err\n");
-                       goto err;
-               }
-       }
-
-       ret = ov2722_get_intg_factor(client, ov2722_info,
-                                       &ov2722_res[dev->fmt_idx]);
-       if (ret)
-               dev_err(&client->dev, "failed to get integration_factor\n");
-
-err:
-       mutex_unlock(&dev->input_lock);
-       return ret;
-}
-static int ov2722_get_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
-                         struct v4l2_subdev_format *format)
-{
-       struct v4l2_mbus_framefmt *fmt = &format->format;
-       struct ov2722_device *dev = to_ov2722_sensor(sd);
-
-       if (format->pad)
-               return -EINVAL;
-       if (!fmt)
-               return -EINVAL;
-
-       fmt->width = ov2722_res[dev->fmt_idx].width;
-       fmt->height = ov2722_res[dev->fmt_idx].height;
-       fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
-
-       return 0;
-}
-
-static int ov2722_detect(struct i2c_client *client)
-{
-       struct i2c_adapter *adapter = client->adapter;
-       u16 high, low;
-       int ret;
-       u16 id;
-       u8 revision;
-
-       if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
-               return -ENODEV;
-
-       ret = ov2722_read_reg(client, OV2722_8BIT,
-                                       OV2722_SC_CMMN_CHIP_ID_H, &high);
-       if (ret) {
-               dev_err(&client->dev, "sensor_id_high = 0x%x\n", high);
-               return -ENODEV;
-       }
-       ret = ov2722_read_reg(client, OV2722_8BIT,
-                                       OV2722_SC_CMMN_CHIP_ID_L, &low);
-       id = (high << 8) | low;
-
-       if ((id != OV2722_ID) && (id != OV2720_ID)) {
-               dev_err(&client->dev, "sensor ID error\n");
-               return -ENODEV;
-       }
-
-       ret = ov2722_read_reg(client, OV2722_8BIT,
-                                       OV2722_SC_CMMN_SUB_ID, &high);
-       revision = (u8) high & 0x0f;
-
-       dev_dbg(&client->dev, "sensor_revision = 0x%x\n", revision);
-       dev_dbg(&client->dev, "detect ov2722 success\n");
-       return 0;
-}
-
-static int ov2722_s_stream(struct v4l2_subdev *sd, int enable)
-{
-       struct ov2722_device *dev = to_ov2722_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret;
-
-       mutex_lock(&dev->input_lock);
-
-       ret = ov2722_write_reg(client, OV2722_8BIT, OV2722_SW_STREAM,
-                               enable ? OV2722_START_STREAMING :
-                               OV2722_STOP_STREAMING);
-
-       mutex_unlock(&dev->input_lock);
-       return ret;
-}
-
-static int ov2722_s_config(struct v4l2_subdev *sd,
-                          int irq, void *platform_data)
-{
-       struct ov2722_device *dev = to_ov2722_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret = 0;
-
-       if (!platform_data)
-               return -ENODEV;
-
-       dev->platform_data =
-               (struct camera_sensor_platform_data *)platform_data;
-
-       mutex_lock(&dev->input_lock);
-       if (dev->platform_data->platform_init) {
-               ret = dev->platform_data->platform_init(client);
-               if (ret) {
-                       dev_err(&client->dev, "platform init err\n");
-                       goto platform_init_failed;
-               }
-       }
-
-       /* power off the module, then power on it in future
-        * as first power on by board may not fulfill the
-        * power on sequqence needed by the module
-        */
-       ret = power_down(sd);
-       if (ret) {
-               dev_err(&client->dev, "ov2722 power-off err.\n");
-               goto fail_power_off;
-       }
-
-       ret = power_up(sd);
-       if (ret) {
-               dev_err(&client->dev, "ov2722 power-up err.\n");
-               goto fail_power_on;
-       }
-
-       ret = dev->platform_data->csi_cfg(sd, 1);
-       if (ret)
-               goto fail_csi_cfg;
-
-       /* config & detect sensor */
-       ret = ov2722_detect(client);
-       if (ret) {
-               dev_err(&client->dev, "ov2722_detect err s_config.\n");
-               goto fail_csi_cfg;
-       }
-
-       /* turn off sensor, after probed */
-       ret = power_down(sd);
-       if (ret) {
-               dev_err(&client->dev, "ov2722 power-off err.\n");
-               goto fail_csi_cfg;
-       }
-       mutex_unlock(&dev->input_lock);
-
-       return 0;
-
-fail_csi_cfg:
-       dev->platform_data->csi_cfg(sd, 0);
-fail_power_on:
-       power_down(sd);
-       dev_err(&client->dev, "sensor power-gating failed\n");
-fail_power_off:
-       if (dev->platform_data->platform_deinit)
-               dev->platform_data->platform_deinit();
-platform_init_failed:
-       mutex_unlock(&dev->input_lock);
-       return ret;
-}
-
-static int ov2722_g_parm(struct v4l2_subdev *sd,
-                       struct v4l2_streamparm *param)
-{
-       struct ov2722_device *dev = to_ov2722_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (!param)
-               return -EINVAL;
-
-       if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-               dev_err(&client->dev,  "unsupported buffer type.\n");
-               return -EINVAL;
-       }
-
-       memset(param, 0, sizeof(*param));
-       param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-       if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) {
-               param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
-               param->parm.capture.timeperframe.numerator = 1;
-               param->parm.capture.capturemode = dev->run_mode;
-               param->parm.capture.timeperframe.denominator =
-                       ov2722_res[dev->fmt_idx].fps;
-       }
-       return 0;
-}
-
-static int ov2722_s_parm(struct v4l2_subdev *sd,
-                       struct v4l2_streamparm *param)
-{
-       struct ov2722_device *dev = to_ov2722_sensor(sd);
-       dev->run_mode = param->parm.capture.capturemode;
-
-       mutex_lock(&dev->input_lock);
-       switch (dev->run_mode) {
-       case CI_MODE_VIDEO:
-               ov2722_res = ov2722_res_video;
-               N_RES = N_RES_VIDEO;
-               break;
-       case CI_MODE_STILL_CAPTURE:
-               ov2722_res = ov2722_res_still;
-               N_RES = N_RES_STILL;
-               break;
-       default:
-               ov2722_res = ov2722_res_preview;
-               N_RES = N_RES_PREVIEW;
-       }
-       mutex_unlock(&dev->input_lock);
-       return 0;
-}
-
-static int ov2722_g_frame_interval(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_frame_interval *interval)
-{
-       struct ov2722_device *dev = to_ov2722_sensor(sd);
-
-       interval->interval.numerator = 1;
-       interval->interval.denominator = ov2722_res[dev->fmt_idx].fps;
-
-       return 0;
-}
-
-static int ov2722_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
-                                struct v4l2_subdev_mbus_code_enum *code)
-{
-       if (code->index >= MAX_FMTS)
-               return -EINVAL;
-
-       code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
-       return 0;
-}
-
-static int ov2722_enum_frame_size(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
-                                 struct v4l2_subdev_frame_size_enum *fse)
-{
-       int index = fse->index;
-
-       if (index >= N_RES)
-               return -EINVAL;
-
-       fse->min_width = ov2722_res[index].width;
-       fse->min_height = ov2722_res[index].height;
-       fse->max_width = ov2722_res[index].width;
-       fse->max_height = ov2722_res[index].height;
-
-       return 0;
-
-}
-
-
-static int ov2722_g_skip_frames(struct v4l2_subdev *sd, u32 *frames)
-{
-       struct ov2722_device *dev = to_ov2722_sensor(sd);
-
-       mutex_lock(&dev->input_lock);
-       *frames = ov2722_res[dev->fmt_idx].skip_frames;
-       mutex_unlock(&dev->input_lock);
-
-       return 0;
-}
-
-static const struct v4l2_subdev_sensor_ops ov2722_sensor_ops = {
-       .g_skip_frames  = ov2722_g_skip_frames,
-};
-
-static const struct v4l2_subdev_video_ops ov2722_video_ops = {
-       .s_stream = ov2722_s_stream,
-       .g_parm = ov2722_g_parm,
-       .s_parm = ov2722_s_parm,
-       .g_frame_interval = ov2722_g_frame_interval,
-};
-
-static const struct v4l2_subdev_core_ops ov2722_core_ops = {
-       .s_power = ov2722_s_power,
-       .ioctl = ov2722_ioctl,
-};
-
-static const struct v4l2_subdev_pad_ops ov2722_pad_ops = {
-       .enum_mbus_code = ov2722_enum_mbus_code,
-       .enum_frame_size = ov2722_enum_frame_size,
-       .get_fmt = ov2722_get_fmt,
-       .set_fmt = ov2722_set_fmt,
-};
-
-static const struct v4l2_subdev_ops ov2722_ops = {
-       .core = &ov2722_core_ops,
-       .video = &ov2722_video_ops,
-       .pad = &ov2722_pad_ops,
-       .sensor = &ov2722_sensor_ops,
-};
-
-static int ov2722_remove(struct i2c_client *client)
-{
-       struct v4l2_subdev *sd = i2c_get_clientdata(client);
-       struct ov2722_device *dev = to_ov2722_sensor(sd);
-       dev_dbg(&client->dev, "ov2722_remove...\n");
-
-       if (dev->platform_data->platform_deinit)
-               dev->platform_data->platform_deinit();
-
-       dev->platform_data->csi_cfg(sd, 0);
-       v4l2_ctrl_handler_free(&dev->ctrl_handler);
-       v4l2_device_unregister_subdev(sd);
-
-       atomisp_gmin_remove_subdev(sd);
-
-       media_entity_cleanup(&dev->sd.entity);
-       kfree(dev);
-
-       return 0;
-}
-
-static int __ov2722_init_ctrl_handler(struct ov2722_device *dev)
-{
-       struct v4l2_ctrl_handler *hdl;
-       unsigned int i;
-       hdl = &dev->ctrl_handler;
-       v4l2_ctrl_handler_init(&dev->ctrl_handler, ARRAY_SIZE(ov2722_controls));
-       for (i = 0; i < ARRAY_SIZE(ov2722_controls); i++)
-               v4l2_ctrl_new_custom(&dev->ctrl_handler, &ov2722_controls[i],
-                                    NULL);
-
-       dev->link_freq = v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_LINK_FREQ);
-
-       if (dev->ctrl_handler.error || !dev->link_freq)
-               return dev->ctrl_handler.error;
-
-       dev->sd.ctrl_handler = hdl;
-
-       return 0;
-}
-
-static int ov2722_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
-{
-       struct ov2722_device *dev;
-       void *ovpdev;
-       int ret;
-       struct acpi_device *adev;
-
-       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-       if (!dev) {
-               dev_err(&client->dev, "out of memory\n");
-               return -ENOMEM;
-       }
-
-       mutex_init(&dev->input_lock);
-
-       dev->fmt_idx = 0;
-       v4l2_i2c_subdev_init(&(dev->sd), client, &ov2722_ops);
-
-       ovpdev = client->dev.platform_data;
-       adev = ACPI_COMPANION(&client->dev);
-       if (adev) {
-               adev->power.flags.power_resources = 0;
-               ovpdev = gmin_camera_platform_data(&dev->sd,
-                                                  ATOMISP_INPUT_FORMAT_RAW_10,
-                                                  atomisp_bayer_order_grbg);
-       }
-
-       ret = ov2722_s_config(&dev->sd, client->irq, ovpdev);
-       if (ret)
-               goto out_free;
-
-       ret = __ov2722_init_ctrl_handler(dev);
-       if (ret)
-               goto out_ctrl_handler_free;
-
-       dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-       dev->pad.flags = MEDIA_PAD_FL_SOURCE;
-       dev->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
-       dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
-
-       ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad);
-       if (ret)
-               ov2722_remove(client);
-
-       if (ACPI_HANDLE(&client->dev))
-               ret = atomisp_register_i2c_module(&dev->sd, ovpdev, RAW_CAMERA);
-
-       return ret;
-
-out_ctrl_handler_free:
-       v4l2_ctrl_handler_free(&dev->ctrl_handler);
-
-out_free:
-       v4l2_device_unregister_subdev(&dev->sd);
-       kfree(dev);
-       return ret;
-}
-
-MODULE_DEVICE_TABLE(i2c, ov2722_id);
-
-static const struct acpi_device_id ov2722_acpi_match[] = {
-       { "INT33FB" },
-       {},
-};
-
-MODULE_DEVICE_TABLE(acpi, ov2722_acpi_match);
-
-static struct i2c_driver ov2722_driver = {
-       .driver = {
-               .name = OV2722_NAME,
-               .acpi_match_table = ACPI_PTR(ov2722_acpi_match),
-       },
-       .probe = ov2722_probe,
-       .remove = ov2722_remove,
-       .id_table = ov2722_id,
-};
-
-static int init_ov2722(void)
-{
-       return i2c_add_driver(&ov2722_driver);
-}
-
-static void exit_ov2722(void)
-{
-
-       i2c_del_driver(&ov2722_driver);
-}
-
-module_init(init_ov2722);
-module_exit(exit_ov2722);
-
-MODULE_AUTHOR("Wei Liu <wei.liu@intel.com>");
-MODULE_DESCRIPTION("A low-level driver for OmniVision 2722 sensors");
-MODULE_LICENSE("GPL");
index 9e8d32521e7ed21b6a7c309fc3f6cd471ce1e4b1..5fe4113bbf08575ef9387c1278810530f8e335e3 100644 (file)
@@ -1,4 +1,4 @@
-config VIDEO_OV5693
+config VIDEO_ATOMISP_OV5693
        tristate "Omnivision ov5693 sensor support"
        depends on I2C && VIDEO_V4L2
        ---help---
index 4e3833aaec05fa5b3d9a0f83bb7ed4905b38584e..2de70003658adf7aa532f97c9fb0cd7d4b1158f8 100644 (file)
@@ -1,4 +1,4 @@
-obj-$(CONFIG_VIDEO_OV5693) += ov5693.o
+obj-$(CONFIG_VIDEO_ATOMISP_OV5693) += atomisp-ov5693.o
 
 # HACK! While this driver is in bad shape, don't enable several warnings
 #       that would be otherwise enabled with W=1
diff --git a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c
new file mode 100644 (file)
index 0000000..2195011
--- /dev/null
@@ -0,0 +1,2059 @@
+/*
+ * Support for OmniVision OV5693 1080p HD camera sensor.
+ *
+ * Copyright (c) 2013 Intel Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kmod.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/moduleparam.h>
+#include <media/v4l2-device.h>
+#include <linux/io.h>
+#include <linux/acpi.h>
+#include "../../include/linux/atomisp_gmin_platform.h"
+
+#include "ov5693.h"
+#include "ad5823.h"
+
+#define __cci_delay(t) \
+       do { \
+               if ((t) < 10) { \
+                       usleep_range((t) * 1000, ((t) + 1) * 1000); \
+               } else { \
+                       msleep((t)); \
+               } \
+       } while (0)
+
+/* Value 30ms reached through experimentation on byt ecs.
+ * The DS specifies a much lower value but when using a smaller value
+ * the I2C bus sometimes locks up permanently when starting the camera.
+ * This issue could not be reproduced on cht, so we can reduce the
+ * delay value to a lower value when insmod.
+ */
+static uint up_delay = 30;
+module_param(up_delay, uint, 0644);
+MODULE_PARM_DESC(up_delay, "Delay prior to the first CCI transaction for ov5693");
+
+static int vcm_ad_i2c_wr8(struct i2c_client *client, u8 reg, u8 val)
+{
+       int err;
+       struct i2c_msg msg;
+       u8 buf[2];
+
+       buf[0] = reg;
+       buf[1] = val;
+
+       msg.addr = VCM_ADDR;
+       msg.flags = 0;
+       msg.len = 2;
+       msg.buf = &buf[0];
+
+       err = i2c_transfer(client->adapter, &msg, 1);
+       if (err != 1) {
+               dev_err(&client->dev, "%s: vcm i2c fail, err code = %d\n",
+                       __func__, err);
+               return -EIO;
+       }
+       return 0;
+}
+
+static int ad5823_i2c_write(struct i2c_client *client, u8 reg, u8 val)
+{
+       struct i2c_msg msg;
+       u8 buf[2];
+       buf[0] = reg;
+       buf[1] = val;
+       msg.addr = AD5823_VCM_ADDR;
+       msg.flags = 0;
+       msg.len = 0x02;
+       msg.buf = &buf[0];
+
+       if (i2c_transfer(client->adapter, &msg, 1) != 1)
+               return -EIO;
+       return 0;
+}
+
+static int ad5823_i2c_read(struct i2c_client *client, u8 reg, u8 *val)
+{
+       struct i2c_msg msg[2];
+       u8 buf[2];
+       buf[0] = reg;
+       buf[1] = 0;
+
+       msg[0].addr = AD5823_VCM_ADDR;
+       msg[0].flags = 0;
+       msg[0].len = 0x01;
+       msg[0].buf = &buf[0];
+
+       msg[1].addr = 0x0c;
+       msg[1].flags = I2C_M_RD;
+       msg[1].len = 0x01;
+       msg[1].buf = &buf[1];
+       *val = 0;
+       if (i2c_transfer(client->adapter, msg, 2) != 2)
+               return -EIO;
+       *val = buf[1];
+       return 0;
+}
+
+
+static const uint32_t ov5693_embedded_effective_size = 28;
+
+/* i2c read/write stuff */
+static int ov5693_read_reg(struct i2c_client *client,
+                          u16 data_length, u16 reg, u16 *val)
+{
+       int err;
+       struct i2c_msg msg[2];
+       unsigned char data[6];
+
+       if (!client->adapter) {
+               dev_err(&client->dev, "%s error, no client->adapter\n",
+                       __func__);
+               return -ENODEV;
+       }
+
+       if (data_length != OV5693_8BIT && data_length != OV5693_16BIT
+                                       && data_length != OV5693_32BIT) {
+               dev_err(&client->dev, "%s error, invalid data length\n",
+                       __func__);
+               return -EINVAL;
+       }
+
+       memset(msg, 0, sizeof(msg));
+
+       msg[0].addr = client->addr;
+       msg[0].flags = 0;
+       msg[0].len = I2C_MSG_LENGTH;
+       msg[0].buf = data;
+
+       /* high byte goes out first */
+       data[0] = (u8)(reg >> 8);
+       data[1] = (u8)(reg & 0xff);
+
+       msg[1].addr = client->addr;
+       msg[1].len = data_length;
+       msg[1].flags = I2C_M_RD;
+       msg[1].buf = data;
+
+       err = i2c_transfer(client->adapter, msg, 2);
+       if (err != 2) {
+               if (err >= 0)
+                       err = -EIO;
+               dev_err(&client->dev,
+                       "read from offset 0x%x error %d", reg, err);
+               return err;
+       }
+
+       *val = 0;
+       /* high byte comes first */
+       if (data_length == OV5693_8BIT)
+               *val = (u8)data[0];
+       else if (data_length == OV5693_16BIT)
+               *val = be16_to_cpu(*(u16 *)&data[0]);
+       else
+               *val = be32_to_cpu(*(u32 *)&data[0]);
+
+       return 0;
+}
+
+static int ov5693_i2c_write(struct i2c_client *client, u16 len, u8 *data)
+{
+       struct i2c_msg msg;
+       const int num_msg = 1;
+       int ret;
+
+       msg.addr = client->addr;
+       msg.flags = 0;
+       msg.len = len;
+       msg.buf = data;
+       ret = i2c_transfer(client->adapter, &msg, 1);
+
+       return ret == num_msg ? 0 : -EIO;
+}
+
+static int vcm_dw_i2c_write(struct i2c_client *client, u16 data)
+{
+       struct i2c_msg msg;
+       const int num_msg = 1;
+       int ret;
+       u16 val;
+
+       val = cpu_to_be16(data);
+       msg.addr = VCM_ADDR;
+       msg.flags = 0;
+       msg.len = OV5693_16BIT;
+       msg.buf = (u8 *)&val;
+
+       ret = i2c_transfer(client->adapter, &msg, 1);
+
+       return ret == num_msg ? 0 : -EIO;
+}
+
+/* Theory: per datasheet, the two VCMs both allow for a 2-byte read.
+ * The DW9714 doesn't actually specify what this does (it has a
+ * two-byte write-only protocol, but specifies the read sequence as
+ * legal), but it returns the same data (zeroes) always, after an
+ * undocumented initial NAK.  The AD5823 has a one-byte address
+ * register to which all writes go, and subsequent reads will cycle
+ * through the 8 bytes of registers.  Notably, the default values (the
+ * device is always power-cycled affirmatively, so we can rely on
+ * these) in AD5823 are not pairwise repetitions of the same 16 bit
+ * word.  So all we have to do is sequentially read two bytes at a
+ * time and see if we detect a difference in any of the first four
+ * pairs.  */
+static int vcm_detect(struct i2c_client *client)
+{
+       int i, ret;
+       struct i2c_msg msg;
+       u16 data0 = 0, data;
+       for (i = 0; i < 4; i++) {
+               msg.addr = VCM_ADDR;
+               msg.flags = I2C_M_RD;
+               msg.len = sizeof(data);
+               msg.buf = (u8 *)&data;
+               ret = i2c_transfer(client->adapter, &msg, 1);
+
+               /* DW9714 always fails the first read and returns
+                * zeroes for subsequent ones */
+               if (i == 0 && ret == -EREMOTEIO) {
+                       data0 = 0;
+                       continue;
+               }
+
+               if (i == 0)
+                       data0 = data;
+
+               if (data != data0)
+                       return VCM_AD5823;
+       }
+       return ret == 1 ? VCM_DW9714 : ret;
+}
+
+static int ov5693_write_reg(struct i2c_client *client, u16 data_length,
+                                                       u16 reg, u16 val)
+{
+       int ret;
+       unsigned char data[4] = {0};
+       u16 *wreg = (u16 *)data;
+       const u16 len = data_length + sizeof(u16); /* 16-bit address + data */
+
+       if (data_length != OV5693_8BIT && data_length != OV5693_16BIT) {
+               dev_err(&client->dev,
+                       "%s error, invalid data_length\n", __func__);
+               return -EINVAL;
+       }
+
+       /* high byte goes out first */
+       *wreg = cpu_to_be16(reg);
+
+       if (data_length == OV5693_8BIT) {
+               data[2] = (u8)(val);
+       } else {
+               /* OV5693_16BIT */
+               u16 *wdata = (u16 *)&data[2];
+               *wdata = cpu_to_be16(val);
+       }
+
+       ret = ov5693_i2c_write(client, len, data);
+       if (ret)
+               dev_err(&client->dev,
+                       "write error: wrote 0x%x to offset 0x%x error %d",
+                       val, reg, ret);
+
+       return ret;
+}
+
+/*
+ * ov5693_write_reg_array - Initializes a list of OV5693 registers
+ * @client: i2c driver client structure
+ * @reglist: list of registers to be written
+ *
+ * This function initializes a list of registers. When consecutive addresses
+ * are found in a row on the list, this function creates a buffer and sends
+ * consecutive data in a single i2c_transfer().
+ *
+ * __ov5693_flush_reg_array, __ov5693_buf_reg_array() and
+ * __ov5693_write_reg_is_consecutive() are internal functions to
+ * ov5693_write_reg_array_fast() and should be not used anywhere else.
+ *
+ */
+
+static int __ov5693_flush_reg_array(struct i2c_client *client,
+                                   struct ov5693_write_ctrl *ctrl)
+{
+       u16 size;
+
+       if (ctrl->index == 0)
+               return 0;
+
+       size = sizeof(u16) + ctrl->index; /* 16-bit address + data */
+       ctrl->buffer.addr = cpu_to_be16(ctrl->buffer.addr);
+       ctrl->index = 0;
+
+       return ov5693_i2c_write(client, size, (u8 *)&ctrl->buffer);
+}
+
+static int __ov5693_buf_reg_array(struct i2c_client *client,
+                                 struct ov5693_write_ctrl *ctrl,
+                                 const struct ov5693_reg *next)
+{
+       int size;
+       u16 *data16;
+
+       switch (next->type) {
+       case OV5693_8BIT:
+               size = 1;
+               ctrl->buffer.data[ctrl->index] = (u8)next->val;
+               break;
+       case OV5693_16BIT:
+               size = 2;
+               data16 = (u16 *)&ctrl->buffer.data[ctrl->index];
+               *data16 = cpu_to_be16((u16)next->val);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* When first item is added, we need to store its starting address */
+       if (ctrl->index == 0)
+               ctrl->buffer.addr = next->reg;
+
+       ctrl->index += size;
+
+       /*
+        * Buffer cannot guarantee free space for u32? Better flush it to avoid
+        * possible lack of memory for next item.
+        */
+       if (ctrl->index + sizeof(u16) >= OV5693_MAX_WRITE_BUF_SIZE)
+               return __ov5693_flush_reg_array(client, ctrl);
+
+       return 0;
+}
+
+static int __ov5693_write_reg_is_consecutive(struct i2c_client *client,
+                                            struct ov5693_write_ctrl *ctrl,
+                                            const struct ov5693_reg *next)
+{
+       if (ctrl->index == 0)
+               return 1;
+
+       return ctrl->buffer.addr + ctrl->index == next->reg;
+}
+
+static int ov5693_write_reg_array(struct i2c_client *client,
+                                 const struct ov5693_reg *reglist)
+{
+       const struct ov5693_reg *next = reglist;
+       struct ov5693_write_ctrl ctrl;
+       int err;
+
+       ctrl.index = 0;
+       for (; next->type != OV5693_TOK_TERM; next++) {
+               switch (next->type & OV5693_TOK_MASK) {
+               case OV5693_TOK_DELAY:
+                       err = __ov5693_flush_reg_array(client, &ctrl);
+                       if (err)
+                               return err;
+                       msleep(next->val);
+                       break;
+               default:
+                       /*
+                        * If next address is not consecutive, data needs to be
+                        * flushed before proceed.
+                        */
+                       if (!__ov5693_write_reg_is_consecutive(client, &ctrl,
+                                                               next)) {
+                               err = __ov5693_flush_reg_array(client, &ctrl);
+                       if (err)
+                               return err;
+                       }
+                       err = __ov5693_buf_reg_array(client, &ctrl, next);
+                       if (err) {
+                               dev_err(&client->dev,
+                                       "%s: write error, aborted\n",
+                                       __func__);
+                               return err;
+                       }
+                       break;
+               }
+       }
+
+       return __ov5693_flush_reg_array(client, &ctrl);
+}
+static int ov5693_g_focal(struct v4l2_subdev *sd, s32 *val)
+{
+       *val = (OV5693_FOCAL_LENGTH_NUM << 16) | OV5693_FOCAL_LENGTH_DEM;
+       return 0;
+}
+
+static int ov5693_g_fnumber(struct v4l2_subdev *sd, s32 *val)
+{
+       /*const f number for imx*/
+       *val = (OV5693_F_NUMBER_DEFAULT_NUM << 16) | OV5693_F_NUMBER_DEM;
+       return 0;
+}
+
+static int ov5693_g_fnumber_range(struct v4l2_subdev *sd, s32 *val)
+{
+       *val = (OV5693_F_NUMBER_DEFAULT_NUM << 24) |
+               (OV5693_F_NUMBER_DEM << 16) |
+               (OV5693_F_NUMBER_DEFAULT_NUM << 8) | OV5693_F_NUMBER_DEM;
+       return 0;
+}
+
+static int ov5693_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val)
+{
+       struct ov5693_device *dev = to_ov5693_sensor(sd);
+
+       *val = ov5693_res[dev->fmt_idx].bin_factor_x;
+
+       return 0;
+}
+
+static int ov5693_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val)
+{
+       struct ov5693_device *dev = to_ov5693_sensor(sd);
+
+       *val = ov5693_res[dev->fmt_idx].bin_factor_y;
+
+       return 0;
+}
+
+static int ov5693_get_intg_factor(struct i2c_client *client,
+                               struct camera_mipi_info *info,
+                               const struct ov5693_resolution *res)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct ov5693_device *dev = to_ov5693_sensor(sd);
+       struct atomisp_sensor_mode_data *buf = &info->data;
+       unsigned int pix_clk_freq_hz;
+       u16 reg_val;
+       int ret;
+
+       if (info == NULL)
+               return -EINVAL;
+
+       /* pixel clock */
+       pix_clk_freq_hz = res->pix_clk_freq * 1000000;
+
+       dev->vt_pix_clk_freq_mhz = pix_clk_freq_hz;
+       buf->vt_pix_clk_freq_mhz = pix_clk_freq_hz;
+
+       /* get integration time */
+       buf->coarse_integration_time_min = OV5693_COARSE_INTG_TIME_MIN;
+       buf->coarse_integration_time_max_margin =
+                                       OV5693_COARSE_INTG_TIME_MAX_MARGIN;
+
+       buf->fine_integration_time_min = OV5693_FINE_INTG_TIME_MIN;
+       buf->fine_integration_time_max_margin =
+                                       OV5693_FINE_INTG_TIME_MAX_MARGIN;
+
+       buf->fine_integration_time_def = OV5693_FINE_INTG_TIME_MIN;
+       buf->frame_length_lines = res->lines_per_frame;
+       buf->line_length_pck = res->pixels_per_line;
+       buf->read_mode = res->bin_mode;
+
+       /* get the cropping and output resolution to ISP for this mode. */
+       ret =  ov5693_read_reg(client, OV5693_16BIT,
+                                       OV5693_HORIZONTAL_START_H, &reg_val);
+       if (ret)
+               return ret;
+       buf->crop_horizontal_start = reg_val;
+
+       ret =  ov5693_read_reg(client, OV5693_16BIT,
+                                       OV5693_VERTICAL_START_H, &reg_val);
+       if (ret)
+               return ret;
+       buf->crop_vertical_start = reg_val;
+
+       ret = ov5693_read_reg(client, OV5693_16BIT,
+                                       OV5693_HORIZONTAL_END_H, &reg_val);
+       if (ret)
+               return ret;
+       buf->crop_horizontal_end = reg_val;
+
+       ret = ov5693_read_reg(client, OV5693_16BIT,
+                                       OV5693_VERTICAL_END_H, &reg_val);
+       if (ret)
+               return ret;
+       buf->crop_vertical_end = reg_val;
+
+       ret = ov5693_read_reg(client, OV5693_16BIT,
+                               OV5693_HORIZONTAL_OUTPUT_SIZE_H, &reg_val);
+       if (ret)
+               return ret;
+       buf->output_width = reg_val;
+
+       ret = ov5693_read_reg(client, OV5693_16BIT,
+                               OV5693_VERTICAL_OUTPUT_SIZE_H, &reg_val);
+       if (ret)
+               return ret;
+       buf->output_height = reg_val;
+
+       buf->binning_factor_x = res->bin_factor_x ?
+                                       res->bin_factor_x : 1;
+       buf->binning_factor_y = res->bin_factor_y ?
+                                       res->bin_factor_y : 1;
+       return 0;
+}
+
+static long __ov5693_set_exposure(struct v4l2_subdev *sd, int coarse_itg,
+                                int gain, int digitgain)
+
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct ov5693_device *dev = to_ov5693_sensor(sd);
+       u16 vts, hts;
+       int ret, exp_val;
+
+       hts = ov5693_res[dev->fmt_idx].pixels_per_line;
+       vts = ov5693_res[dev->fmt_idx].lines_per_frame;
+       /*If coarse_itg is larger than 1<<15, can not write to reg directly.
+         The way is to write coarse_itg/2 to the reg, meanwhile write 2*hts
+         to the reg. */
+       if (coarse_itg > (1 << 15)) {
+               hts = hts * 2;
+               coarse_itg = (int)coarse_itg / 2;
+       }
+       /* group hold */
+       ret = ov5693_write_reg(client, OV5693_8BIT,
+                               OV5693_GROUP_ACCESS, 0x00);
+       if (ret) {
+               dev_err(&client->dev, "%s: write %x error, aborted\n",
+                       __func__, OV5693_GROUP_ACCESS);
+               return ret;
+       }
+
+       ret = ov5693_write_reg(client, OV5693_8BIT,
+                               OV5693_TIMING_HTS_H, (hts >> 8) & 0xFF);
+       if (ret) {
+               dev_err(&client->dev, "%s: write %x error, aborted\n",
+                       __func__, OV5693_TIMING_HTS_H);
+               return ret;
+       }
+
+       ret = ov5693_write_reg(client, OV5693_8BIT,
+                               OV5693_TIMING_HTS_L, hts & 0xFF);
+       if (ret) {
+               dev_err(&client->dev, "%s: write %x error, aborted\n",
+                       __func__, OV5693_TIMING_HTS_L);
+               return ret;
+       }
+       /* Increase the VTS to match exposure + MARGIN */
+       if (coarse_itg > vts - OV5693_INTEGRATION_TIME_MARGIN)
+               vts = (u16) coarse_itg + OV5693_INTEGRATION_TIME_MARGIN;
+
+       ret = ov5693_write_reg(client, OV5693_8BIT,
+                               OV5693_TIMING_VTS_H, (vts >> 8) & 0xFF);
+       if (ret) {
+               dev_err(&client->dev, "%s: write %x error, aborted\n",
+                       __func__, OV5693_TIMING_VTS_H);
+               return ret;
+       }
+
+       ret = ov5693_write_reg(client, OV5693_8BIT,
+                                       OV5693_TIMING_VTS_L, vts & 0xFF);
+       if (ret) {
+               dev_err(&client->dev, "%s: write %x error, aborted\n",
+                       __func__, OV5693_TIMING_VTS_L);
+               return ret;
+       }
+
+       /* set exposure */
+
+       /* Lower four bit should be 0*/
+       exp_val = coarse_itg << 4;
+       ret = ov5693_write_reg(client, OV5693_8BIT,
+                              OV5693_EXPOSURE_L, exp_val & 0xFF);
+       if (ret) {
+               dev_err(&client->dev, "%s: write %x error, aborted\n",
+                       __func__, OV5693_EXPOSURE_L);
+               return ret;
+       }
+
+       ret = ov5693_write_reg(client, OV5693_8BIT,
+                              OV5693_EXPOSURE_M, (exp_val >> 8) & 0xFF);
+       if (ret) {
+               dev_err(&client->dev, "%s: write %x error, aborted\n",
+                       __func__, OV5693_EXPOSURE_M);
+               return ret;
+       }
+
+       ret = ov5693_write_reg(client, OV5693_8BIT,
+                              OV5693_EXPOSURE_H, (exp_val >> 16) & 0x0F);
+       if (ret) {
+               dev_err(&client->dev, "%s: write %x error, aborted\n",
+                       __func__, OV5693_EXPOSURE_H);
+               return ret;
+       }
+
+       /* Analog gain */
+       ret = ov5693_write_reg(client, OV5693_8BIT,
+                               OV5693_AGC_L, gain & 0xff);
+       if (ret) {
+               dev_err(&client->dev, "%s: write %x error, aborted\n",
+                       __func__, OV5693_AGC_L);
+               return ret;
+       }
+
+       ret = ov5693_write_reg(client, OV5693_8BIT,
+                               OV5693_AGC_H, (gain >> 8) & 0xff);
+       if (ret) {
+               dev_err(&client->dev, "%s: write %x error, aborted\n",
+                       __func__, OV5693_AGC_H);
+               return ret;
+       }
+
+       /* Digital gain */
+       if (digitgain) {
+               ret = ov5693_write_reg(client, OV5693_16BIT,
+                               OV5693_MWB_RED_GAIN_H, digitgain);
+               if (ret) {
+                       dev_err(&client->dev, "%s: write %x error, aborted\n",
+                               __func__, OV5693_MWB_RED_GAIN_H);
+                       return ret;
+               }
+
+               ret = ov5693_write_reg(client, OV5693_16BIT,
+                               OV5693_MWB_GREEN_GAIN_H, digitgain);
+               if (ret) {
+                       dev_err(&client->dev, "%s: write %x error, aborted\n",
+                               __func__, OV5693_MWB_RED_GAIN_H);
+                       return ret;
+               }
+
+               ret = ov5693_write_reg(client, OV5693_16BIT,
+                               OV5693_MWB_BLUE_GAIN_H, digitgain);
+               if (ret) {
+                       dev_err(&client->dev, "%s: write %x error, aborted\n",
+                               __func__, OV5693_MWB_RED_GAIN_H);
+                       return ret;
+               }
+       }
+
+       /* End group */
+       ret = ov5693_write_reg(client, OV5693_8BIT,
+                               OV5693_GROUP_ACCESS, 0x10);
+       if (ret)
+               return ret;
+
+       /* Delay launch group */
+       ret = ov5693_write_reg(client, OV5693_8BIT,
+                               OV5693_GROUP_ACCESS, 0xa0);
+       if (ret)
+               return ret;
+       return ret;
+}
+
+static int ov5693_set_exposure(struct v4l2_subdev *sd, int exposure,
+       int gain, int digitgain)
+{
+       struct ov5693_device *dev = to_ov5693_sensor(sd);
+       int ret;
+
+       mutex_lock(&dev->input_lock);
+       ret = __ov5693_set_exposure(sd, exposure, gain, digitgain);
+       mutex_unlock(&dev->input_lock);
+
+       return ret;
+}
+
+static long ov5693_s_exposure(struct v4l2_subdev *sd,
+                              struct atomisp_exposure *exposure)
+{
+       u16 coarse_itg = exposure->integration_time[0];
+       u16 analog_gain = exposure->gain[0];
+       u16 digital_gain = exposure->gain[1];
+
+       /* we should not accept the invalid value below */
+       if (analog_gain == 0) {
+               struct i2c_client *client = v4l2_get_subdevdata(sd);
+               v4l2_err(client, "%s: invalid value\n", __func__);
+               return -EINVAL;
+       }
+       return ov5693_set_exposure(sd, coarse_itg, analog_gain, digital_gain);
+}
+
+static int ov5693_read_otp_reg_array(struct i2c_client *client, u16 size,
+                                    u16 addr, u8 *buf)
+{
+       u16 index;
+       int ret;
+       u16 *pVal = NULL;
+
+       for (index = 0; index <= size; index++) {
+               pVal = (u16 *) (buf + index);
+               ret =
+                       ov5693_read_reg(client, OV5693_8BIT, addr + index,
+                                   pVal);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int __ov5693_otp_read(struct v4l2_subdev *sd, u8 *buf)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct ov5693_device *dev = to_ov5693_sensor(sd);
+       int ret;
+       int i;
+       u8 *b = buf;
+       dev->otp_size = 0;
+       for (i = 1; i < OV5693_OTP_BANK_MAX; i++) {
+               /*set bank NO and OTP read mode. */
+               ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_OTP_BANK_REG, (i | 0xc0));   //[7:6] 2'b11 [5:0] bank no
+               if (ret) {
+                       dev_err(&client->dev, "failed to prepare OTP page\n");
+                       return ret;
+               }
+               //pr_debug("write 0x%x->0x%x\n",OV5693_OTP_BANK_REG,(i|0xc0));
+
+               /*enable read */
+               ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_OTP_READ_REG, OV5693_OTP_MODE_READ); // enable :1
+               if (ret) {
+                       dev_err(&client->dev,
+                               "failed to set OTP reading mode page");
+                       return ret;
+               }
+               //pr_debug("write 0x%x->0x%x\n",OV5693_OTP_READ_REG,OV5693_OTP_MODE_READ);
+
+               /* Reading the OTP data array */
+               ret = ov5693_read_otp_reg_array(client, OV5693_OTP_BANK_SIZE,
+                                               OV5693_OTP_START_ADDR,
+                                               b);
+               if (ret) {
+                       dev_err(&client->dev, "failed to read OTP data\n");
+                       return ret;
+               }
+
+               //pr_debug("BANK[%2d] %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", i, *b, *(b+1), *(b+2), *(b+3), *(b+4), *(b+5), *(b+6), *(b+7), *(b+8), *(b+9), *(b+10), *(b+11), *(b+12), *(b+13), *(b+14), *(b+15));
+
+               //Intel OTP map, try to read 320byts first.
+               if (21 == i) {
+                       if ((*b) == 0) {
+                               dev->otp_size = 320;
+                               break;
+                       } else {
+                               b = buf;
+                               continue;
+                       }
+               } else if (24 == i) {           //if the first 320bytes data doesn't not exist, try to read the next 32bytes data.
+                       if ((*b) == 0) {
+                               dev->otp_size = 32;
+                               break;
+               } else {
+                               b = buf;
+                               continue;
+                       }
+               } else if (27 == i) {           //if the prvious 32bytes data doesn't exist, try to read the next 32bytes data again.
+                       if ((*b) == 0) {
+                               dev->otp_size = 32;
+                               break;
+                       } else {
+                               dev->otp_size = 0;      // no OTP data.
+                               break;
+                       }
+               }
+
+               b = b + OV5693_OTP_BANK_SIZE;
+       }
+       return 0;
+}
+
+/*
+ * Read otp data and store it into a kmalloced buffer.
+ * The caller must kfree the buffer when no more needed.
+ * @size: set to the size of the returned otp data.
+ */
+static void *ov5693_otp_read(struct v4l2_subdev *sd)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       u8 *buf;
+       int ret;
+
+       buf = devm_kzalloc(&client->dev, (OV5693_OTP_DATA_SIZE + 16), GFP_KERNEL);
+       if (!buf)
+               return ERR_PTR(-ENOMEM);
+
+       //otp valid after mipi on and sw stream on
+       ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_FRAME_OFF_NUM, 0x00);
+
+       ret = ov5693_write_reg(client, OV5693_8BIT,
+                              OV5693_SW_STREAM, OV5693_START_STREAMING);
+
+       ret = __ov5693_otp_read(sd, buf);
+
+       //mipi off and sw stream off after otp read
+       ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_FRAME_OFF_NUM, 0x0f);
+
+       ret = ov5693_write_reg(client, OV5693_8BIT,
+                              OV5693_SW_STREAM, OV5693_STOP_STREAMING);
+
+       /* Driver has failed to find valid data */
+       if (ret) {
+               dev_err(&client->dev, "sensor found no valid OTP data\n");
+               return ERR_PTR(ret);
+       }
+
+       return buf;
+}
+
+static int ov5693_g_priv_int_data(struct v4l2_subdev *sd,
+                                 struct v4l2_private_int_data *priv)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct ov5693_device *dev = to_ov5693_sensor(sd);
+       u8 __user *to = priv->data;
+       u32 read_size = priv->size;
+       int ret;
+
+       /* No need to copy data if size is 0 */
+       if (!read_size)
+               goto out;
+
+       if (IS_ERR(dev->otp_data)) {
+               dev_err(&client->dev, "OTP data not available");
+               return PTR_ERR(dev->otp_data);
+       }
+
+       /* Correct read_size value only if bigger than maximum */
+       if (read_size > OV5693_OTP_DATA_SIZE)
+               read_size = OV5693_OTP_DATA_SIZE;
+
+       ret = copy_to_user(to, dev->otp_data, read_size);
+       if (ret) {
+               dev_err(&client->dev, "%s: failed to copy OTP data to user\n",
+                       __func__);
+               return -EFAULT;
+       }
+
+       pr_debug("%s read_size:%d\n", __func__, read_size);
+
+out:
+       /* Return correct size */
+       priv->size = dev->otp_size;
+
+       return 0;
+
+}
+
+static long ov5693_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+
+       switch (cmd) {
+       case ATOMISP_IOC_S_EXPOSURE:
+               return ov5693_s_exposure(sd, arg);
+       case ATOMISP_IOC_G_SENSOR_PRIV_INT_DATA:
+               return ov5693_g_priv_int_data(sd, arg);
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/* This returns the exposure time being used. This should only be used
+   for filling in EXIF data, not for actual image processing. */
+static int ov5693_q_exposure(struct v4l2_subdev *sd, s32 *value)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       u16 reg_v, reg_v2;
+       int ret;
+
+       /* get exposure */
+       ret = ov5693_read_reg(client, OV5693_8BIT,
+                                       OV5693_EXPOSURE_L,
+                                       &reg_v);
+       if (ret)
+               goto err;
+
+       ret = ov5693_read_reg(client, OV5693_8BIT,
+                                       OV5693_EXPOSURE_M,
+                                       &reg_v2);
+       if (ret)
+               goto err;
+
+       reg_v += reg_v2 << 8;
+       ret = ov5693_read_reg(client, OV5693_8BIT,
+                                       OV5693_EXPOSURE_H,
+                                       &reg_v2);
+       if (ret)
+               goto err;
+
+       *value = reg_v + (((u32)reg_v2 << 16));
+err:
+       return ret;
+}
+
+static int ad5823_t_focus_vcm(struct v4l2_subdev *sd, u16 val)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret = -EINVAL;
+       u8 vcm_code;
+
+       ret = ad5823_i2c_read(client, AD5823_REG_VCM_CODE_MSB, &vcm_code);
+       if (ret)
+               return ret;
+
+       /* set reg VCM_CODE_MSB Bit[1:0] */
+       vcm_code = (vcm_code & VCM_CODE_MSB_MASK) |
+               ((val >> 8) & ~VCM_CODE_MSB_MASK);
+       ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_MSB, vcm_code);
+       if (ret)
+               return ret;
+
+       /* set reg VCM_CODE_LSB Bit[7:0] */
+       ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_LSB, (val & 0xff));
+       if (ret)
+               return ret;
+
+       /* set required vcm move time */
+       vcm_code = AD5823_RESONANCE_PERIOD / AD5823_RESONANCE_COEF
+               - AD5823_HIGH_FREQ_RANGE;
+       ret = ad5823_i2c_write(client, AD5823_REG_VCM_MOVE_TIME, vcm_code);
+
+       return ret;
+}
+
+int ad5823_t_focus_abs(struct v4l2_subdev *sd, s32 value)
+{
+       value = min(value, AD5823_MAX_FOCUS_POS);
+       return ad5823_t_focus_vcm(sd, value);
+}
+
+static int ov5693_t_focus_abs(struct v4l2_subdev *sd, s32 value)
+{
+       struct ov5693_device *dev = to_ov5693_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret = 0;
+
+       dev_dbg(&client->dev, "%s: FOCUS_POS: 0x%x\n", __func__, value);
+       value = clamp(value, 0, OV5693_VCM_MAX_FOCUS_POS);
+       if (dev->vcm == VCM_DW9714) {
+               if (dev->vcm_update) {
+                       ret = vcm_dw_i2c_write(client, VCM_PROTECTION_OFF);
+                       if (ret)
+                               return ret;
+                       ret = vcm_dw_i2c_write(client, DIRECT_VCM);
+                       if (ret)
+                               return ret;
+                       ret = vcm_dw_i2c_write(client, VCM_PROTECTION_ON);
+                       if (ret)
+                               return ret;
+                       dev->vcm_update = false;
+               }
+               ret = vcm_dw_i2c_write(client,
+                                      vcm_val(value, VCM_DEFAULT_S));
+       } else if (dev->vcm == VCM_AD5823) {
+               ad5823_t_focus_abs(sd, value);
+       }
+       if (ret == 0) {
+               dev->number_of_steps = value - dev->focus;
+               dev->focus = value;
+               getnstimeofday(&(dev->timestamp_t_focus_abs));
+       } else
+               dev_err(&client->dev,
+                       "%s: i2c failed. ret %d\n", __func__, ret);
+
+       return ret;
+}
+
+static int ov5693_t_focus_rel(struct v4l2_subdev *sd, s32 value)
+{
+       struct ov5693_device *dev = to_ov5693_sensor(sd);
+       return ov5693_t_focus_abs(sd, dev->focus + value);
+}
+
+#define DELAY_PER_STEP_NS      1000000
+#define DELAY_MAX_PER_STEP_NS  (1000000 * 1023)
+static int ov5693_q_focus_status(struct v4l2_subdev *sd, s32 *value)
+{
+       u32 status = 0;
+       struct ov5693_device *dev = to_ov5693_sensor(sd);
+       struct timespec temptime;
+       const struct timespec timedelay = {
+               0,
+               min((u32)abs(dev->number_of_steps) * DELAY_PER_STEP_NS,
+               (u32)DELAY_MAX_PER_STEP_NS),
+       };
+
+       getnstimeofday(&temptime);
+       temptime = timespec_sub(temptime, (dev->timestamp_t_focus_abs));
+       if (timespec_compare(&temptime, &timedelay) <= 0) {
+               status |= ATOMISP_FOCUS_STATUS_MOVING;
+               status |= ATOMISP_FOCUS_HP_IN_PROGRESS;
+       } else {
+               status |= ATOMISP_FOCUS_STATUS_ACCEPTS_NEW_MOVE;
+               status |= ATOMISP_FOCUS_HP_COMPLETE;
+       }
+
+       *value = status;
+
+       return 0;
+}
+
+static int ov5693_q_focus_abs(struct v4l2_subdev *sd, s32 *value)
+{
+       struct ov5693_device *dev = to_ov5693_sensor(sd);
+       s32 val;
+
+       ov5693_q_focus_status(sd, &val);
+
+       if (val & ATOMISP_FOCUS_STATUS_MOVING)
+               *value  = dev->focus - dev->number_of_steps;
+       else
+               *value  = dev->focus;
+
+       return 0;
+}
+
+static int ov5693_t_vcm_slew(struct v4l2_subdev *sd, s32 value)
+{
+       struct ov5693_device *dev = to_ov5693_sensor(sd);
+       dev->number_of_steps = value;
+       dev->vcm_update = true;
+       return 0;
+}
+
+static int ov5693_t_vcm_timing(struct v4l2_subdev *sd, s32 value)
+{
+       struct ov5693_device *dev = to_ov5693_sensor(sd);
+       dev->number_of_steps = value;
+       dev->vcm_update = true;
+       return 0;
+}
+
+static int ov5693_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct ov5693_device *dev =
+           container_of(ctrl->handler, struct ov5693_device, ctrl_handler);
+       struct i2c_client *client = v4l2_get_subdevdata(&dev->sd);
+       int ret = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_FOCUS_ABSOLUTE:
+               dev_dbg(&client->dev, "%s: CID_FOCUS_ABSOLUTE:%d.\n",
+                       __func__, ctrl->val);
+               ret = ov5693_t_focus_abs(&dev->sd, ctrl->val);
+               break;
+       case V4L2_CID_FOCUS_RELATIVE:
+               dev_dbg(&client->dev, "%s: CID_FOCUS_RELATIVE:%d.\n",
+                       __func__, ctrl->val);
+               ret = ov5693_t_focus_rel(&dev->sd, ctrl->val);
+               break;
+       case V4L2_CID_VCM_SLEW:
+               ret = ov5693_t_vcm_slew(&dev->sd, ctrl->val);
+               break;
+       case V4L2_CID_VCM_TIMEING:
+               ret = ov5693_t_vcm_timing(&dev->sd, ctrl->val);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+       return ret;
+}
+
+static int ov5693_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct ov5693_device *dev =
+           container_of(ctrl->handler, struct ov5693_device, ctrl_handler);
+       int ret = 0;
+
+       switch (ctrl->id) {
+       case V4L2_CID_EXPOSURE_ABSOLUTE:
+               ret = ov5693_q_exposure(&dev->sd, &ctrl->val);
+               break;
+       case V4L2_CID_FOCAL_ABSOLUTE:
+               ret = ov5693_g_focal(&dev->sd, &ctrl->val);
+               break;
+       case V4L2_CID_FNUMBER_ABSOLUTE:
+               ret = ov5693_g_fnumber(&dev->sd, &ctrl->val);
+               break;
+       case V4L2_CID_FNUMBER_RANGE:
+               ret = ov5693_g_fnumber_range(&dev->sd, &ctrl->val);
+               break;
+       case V4L2_CID_FOCUS_ABSOLUTE:
+               ret = ov5693_q_focus_abs(&dev->sd, &ctrl->val);
+               break;
+       case V4L2_CID_FOCUS_STATUS:
+               ret = ov5693_q_focus_status(&dev->sd, &ctrl->val);
+               break;
+       case V4L2_CID_BIN_FACTOR_HORZ:
+               ret = ov5693_g_bin_factor_x(&dev->sd, &ctrl->val);
+               break;
+       case V4L2_CID_BIN_FACTOR_VERT:
+               ret = ov5693_g_bin_factor_y(&dev->sd, &ctrl->val);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static const struct v4l2_ctrl_ops ctrl_ops = {
+       .s_ctrl = ov5693_s_ctrl,
+       .g_volatile_ctrl = ov5693_g_volatile_ctrl
+};
+
+struct v4l2_ctrl_config ov5693_controls[] = {
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_EXPOSURE_ABSOLUTE,
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .name = "exposure",
+        .min = 0x0,
+        .max = 0xffff,
+        .step = 0x01,
+        .def = 0x00,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_FOCAL_ABSOLUTE,
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .name = "focal length",
+        .min = OV5693_FOCAL_LENGTH_DEFAULT,
+        .max = OV5693_FOCAL_LENGTH_DEFAULT,
+        .step = 0x01,
+        .def = OV5693_FOCAL_LENGTH_DEFAULT,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_FNUMBER_ABSOLUTE,
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .name = "f-number",
+        .min = OV5693_F_NUMBER_DEFAULT,
+        .max = OV5693_F_NUMBER_DEFAULT,
+        .step = 0x01,
+        .def = OV5693_F_NUMBER_DEFAULT,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_FNUMBER_RANGE,
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .name = "f-number range",
+        .min = OV5693_F_NUMBER_RANGE,
+        .max = OV5693_F_NUMBER_RANGE,
+        .step = 0x01,
+        .def = OV5693_F_NUMBER_RANGE,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_FOCUS_ABSOLUTE,
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .name = "focus move absolute",
+        .min = 0,
+        .max = OV5693_VCM_MAX_FOCUS_POS,
+        .step = 1,
+        .def = 0,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_FOCUS_RELATIVE,
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .name = "focus move relative",
+        .min = OV5693_VCM_MAX_FOCUS_NEG,
+        .max = OV5693_VCM_MAX_FOCUS_POS,
+        .step = 1,
+        .def = 0,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_FOCUS_STATUS,
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .name = "focus status",
+        .min = 0,
+        .max = 100,            /* allow enum to grow in the future */
+        .step = 1,
+        .def = 0,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_VCM_SLEW,
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .name = "vcm slew",
+        .min = 0,
+        .max = OV5693_VCM_SLEW_STEP_MAX,
+        .step = 1,
+        .def = 0,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_VCM_TIMEING,
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .name = "vcm step time",
+        .min = 0,
+        .max = OV5693_VCM_SLEW_TIME_MAX,
+        .step = 1,
+        .def = 0,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_BIN_FACTOR_HORZ,
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .name = "horizontal binning factor",
+        .min = 0,
+        .max = OV5693_BIN_FACTOR_MAX,
+        .step = 1,
+        .def = 0,
+        .flags = 0,
+        },
+       {
+        .ops = &ctrl_ops,
+        .id = V4L2_CID_BIN_FACTOR_VERT,
+        .type = V4L2_CTRL_TYPE_INTEGER,
+        .name = "vertical binning factor",
+        .min = 0,
+        .max = OV5693_BIN_FACTOR_MAX,
+        .step = 1,
+        .def = 0,
+        .flags = 0,
+        },
+};
+
+static int ov5693_init(struct v4l2_subdev *sd)
+{
+       struct ov5693_device *dev = to_ov5693_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret;
+
+       pr_info("%s\n", __func__);
+       mutex_lock(&dev->input_lock);
+       dev->vcm_update = false;
+
+       if (dev->vcm == VCM_AD5823) {
+               ret = vcm_ad_i2c_wr8(client, 0x01, 0x01); /* vcm init test */
+               if (ret)
+                       dev_err(&client->dev,
+                               "vcm reset failed\n");
+               /*change the mode*/
+               ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_MSB,
+                                      AD5823_RING_CTRL_ENABLE);
+               if (ret)
+                       dev_err(&client->dev,
+                               "vcm enable ringing failed\n");
+               ret = ad5823_i2c_write(client, AD5823_REG_MODE,
+                                       AD5823_ARC_RES1);
+               if (ret)
+                       dev_err(&client->dev,
+                               "vcm change mode failed\n");
+       }
+
+       /*change initial focus value for ad5823*/
+       if (dev->vcm == VCM_AD5823) {
+               dev->focus = AD5823_INIT_FOCUS_POS;
+               ov5693_t_focus_abs(sd, AD5823_INIT_FOCUS_POS);
+       } else {
+               dev->focus = 0;
+               ov5693_t_focus_abs(sd, 0);
+       }
+
+       mutex_unlock(&dev->input_lock);
+
+       return 0;
+}
+
+static int power_ctrl(struct v4l2_subdev *sd, bool flag)
+{
+       int ret;
+       struct ov5693_device *dev = to_ov5693_sensor(sd);
+
+       if (!dev || !dev->platform_data)
+               return -ENODEV;
+
+       /* Non-gmin platforms use the legacy callback */
+       if (dev->platform_data->power_ctrl)
+               return dev->platform_data->power_ctrl(sd, flag);
+
+       /* This driver assumes "internal DVDD, PWDNB tied to DOVDD".
+        * In this set up only gpio0 (XSHUTDN) should be available
+        * but in some products (for example ECS) gpio1 (PWDNB) is
+        * also available. If gpio1 is available we emulate it being
+        * tied to DOVDD here. */
+       if (flag) {
+               ret = dev->platform_data->v2p8_ctrl(sd, 1);
+               dev->platform_data->gpio1_ctrl(sd, 1);
+               if (ret == 0) {
+                       ret = dev->platform_data->v1p8_ctrl(sd, 1);
+                       if (ret) {
+                               dev->platform_data->gpio1_ctrl(sd, 0);
+                               ret = dev->platform_data->v2p8_ctrl(sd, 0);
+                       }
+               }
+       } else {
+               dev->platform_data->gpio1_ctrl(sd, 0);
+               ret = dev->platform_data->v1p8_ctrl(sd, 0);
+               ret |= dev->platform_data->v2p8_ctrl(sd, 0);
+       }
+
+       return ret;
+}
+
+static int gpio_ctrl(struct v4l2_subdev *sd, bool flag)
+{
+       struct ov5693_device *dev = to_ov5693_sensor(sd);
+
+       if (!dev || !dev->platform_data)
+               return -ENODEV;
+
+       /* Non-gmin platforms use the legacy callback */
+       if (dev->platform_data->gpio_ctrl)
+               return dev->platform_data->gpio_ctrl(sd, flag);
+
+       return dev->platform_data->gpio0_ctrl(sd, flag);
+}
+
+static int __power_up(struct v4l2_subdev *sd)
+{
+       struct ov5693_device *dev = to_ov5693_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret;
+
+       if (NULL == dev->platform_data) {
+               dev_err(&client->dev,
+                       "no camera_sensor_platform_data");
+               return -ENODEV;
+       }
+
+       /* power control */
+       ret = power_ctrl(sd, 1);
+       if (ret)
+               goto fail_power;
+
+       /* according to DS, at least 5ms is needed between DOVDD and PWDN */
+       /* add this delay time to 10~11ms*/
+       usleep_range(10000, 11000);
+
+       /* gpio ctrl */
+       ret = gpio_ctrl(sd, 1);
+       if (ret) {
+               ret = gpio_ctrl(sd, 1);
+               if (ret)
+                       goto fail_power;
+       }
+
+       /* flis clock control */
+       ret = dev->platform_data->flisclk_ctrl(sd, 1);
+       if (ret)
+               goto fail_clk;
+
+       __cci_delay(up_delay);
+
+       return 0;
+
+fail_clk:
+       gpio_ctrl(sd, 0);
+fail_power:
+       power_ctrl(sd, 0);
+       dev_err(&client->dev, "sensor power-up failed\n");
+
+       return ret;
+}
+
+static int power_down(struct v4l2_subdev *sd)
+{
+       struct ov5693_device *dev = to_ov5693_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret = 0;
+
+       dev->focus = OV5693_INVALID_CONFIG;
+       if (NULL == dev->platform_data) {
+               dev_err(&client->dev,
+                       "no camera_sensor_platform_data");
+               return -ENODEV;
+       }
+
+       ret = dev->platform_data->flisclk_ctrl(sd, 0);
+       if (ret)
+               dev_err(&client->dev, "flisclk failed\n");
+
+       /* gpio ctrl */
+       ret = gpio_ctrl(sd, 0);
+       if (ret) {
+               ret = gpio_ctrl(sd, 0);
+               if (ret)
+                       dev_err(&client->dev, "gpio failed 2\n");
+       }
+
+       /* power control */
+       ret = power_ctrl(sd, 0);
+       if (ret)
+               dev_err(&client->dev, "vprog failed.\n");
+
+       return ret;
+}
+
+static int power_up(struct v4l2_subdev *sd)
+{
+       static const int retry_count = 4;
+       int i, ret;
+
+       for (i = 0; i < retry_count; i++) {
+               ret = __power_up(sd);
+               if (!ret)
+                       return 0;
+
+               power_down(sd);
+       }
+       return ret;
+}
+
+static int ov5693_s_power(struct v4l2_subdev *sd, int on)
+{
+       int ret;
+
+       pr_info("%s: on %d\n", __func__, on);
+       if (on == 0)
+               return power_down(sd);
+       else {
+               ret = power_up(sd);
+               if (!ret) {
+                       ret = ov5693_init(sd);
+                       /* restore settings */
+                       ov5693_res = ov5693_res_preview;
+                       N_RES = N_RES_PREVIEW;
+               }
+       }
+       return ret;
+}
+
+/*
+ * distance - calculate the distance
+ * @res: resolution
+ * @w: width
+ * @h: height
+ *
+ * Get the gap between res_w/res_h and w/h.
+ * distance = (res_w/res_h - w/h) / (w/h) * 8192
+ * res->width/height smaller than w/h wouldn't be considered.
+ * The gap of ratio larger than 1/8 wouldn't be considered.
+ * Returns the value of gap or -1 if fail.
+ */
+#define LARGEST_ALLOWED_RATIO_MISMATCH 1024
+static int distance(struct ov5693_resolution *res, u32 w, u32 h)
+{
+       int ratio;
+       int distance;
+
+       if (w == 0 || h == 0 ||
+           res->width < w || res->height < h)
+               return -1;
+
+       ratio = res->width << 13;
+       ratio /= w;
+       ratio *= h;
+       ratio /= res->height;
+
+       distance = abs(ratio - 8192);
+
+       if (distance > LARGEST_ALLOWED_RATIO_MISMATCH)
+               return -1;
+
+       return distance;
+}
+
+/* Return the nearest higher resolution index
+ * Firstly try to find the approximate aspect ratio resolution
+ * If we find multiple same AR resolutions, choose the
+ * minimal size.
+ */
+static int nearest_resolution_index(int w, int h)
+{
+       int i;
+       int idx = -1;
+       int dist;
+       int min_dist = INT_MAX;
+       int min_res_w = INT_MAX;
+       struct ov5693_resolution *tmp_res = NULL;
+
+       for (i = 0; i < N_RES; i++) {
+               tmp_res = &ov5693_res[i];
+               dist = distance(tmp_res, w, h);
+               if (dist == -1)
+                       continue;
+               if (dist < min_dist) {
+                       min_dist = dist;
+                       idx = i;
+                       min_res_w = ov5693_res[i].width;
+                       continue;
+               }
+               if (dist == min_dist && ov5693_res[i].width < min_res_w)
+                       idx = i;
+       }
+
+       return idx;
+}
+
+static int get_resolution_index(int w, int h)
+{
+       int i;
+
+       for (i = 0; i < N_RES; i++) {
+               if (w != ov5693_res[i].width)
+                       continue;
+               if (h != ov5693_res[i].height)
+                       continue;
+
+               return i;
+       }
+
+       return -1;
+}
+
+/* TODO: remove it. */
+static int startup(struct v4l2_subdev *sd)
+{
+       struct ov5693_device *dev = to_ov5693_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret = 0;
+
+       ret = ov5693_write_reg(client, OV5693_8BIT,
+                                       OV5693_SW_RESET, 0x01);
+       if (ret) {
+               dev_err(&client->dev, "ov5693 reset err.\n");
+               return ret;
+       }
+
+       ret = ov5693_write_reg_array(client, ov5693_global_setting);
+       if (ret) {
+               dev_err(&client->dev, "ov5693 write register err.\n");
+               return ret;
+       }
+
+       ret = ov5693_write_reg_array(client, ov5693_res[dev->fmt_idx].regs);
+       if (ret) {
+               dev_err(&client->dev, "ov5693 write register err.\n");
+               return ret;
+       }
+
+       return ret;
+}
+
+static int ov5693_set_fmt(struct v4l2_subdev *sd,
+                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_format *format)
+{
+       struct v4l2_mbus_framefmt *fmt = &format->format;
+       struct ov5693_device *dev = to_ov5693_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct camera_mipi_info *ov5693_info = NULL;
+       int ret = 0;
+       int idx;
+       if (format->pad)
+               return -EINVAL;
+       if (!fmt)
+               return -EINVAL;
+       ov5693_info = v4l2_get_subdev_hostdata(sd);
+       if (ov5693_info == NULL)
+               return -EINVAL;
+
+       mutex_lock(&dev->input_lock);
+       idx = nearest_resolution_index(fmt->width, fmt->height);
+       if (idx == -1) {
+               /* return the largest resolution */
+               fmt->width = ov5693_res[N_RES - 1].width;
+               fmt->height = ov5693_res[N_RES - 1].height;
+       } else {
+               fmt->width = ov5693_res[idx].width;
+               fmt->height = ov5693_res[idx].height;
+       }
+
+       fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
+       if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+               cfg->try_fmt = *fmt;
+               mutex_unlock(&dev->input_lock);
+               return 0;
+       }
+
+       dev->fmt_idx = get_resolution_index(fmt->width, fmt->height);
+       if (dev->fmt_idx == -1) {
+               dev_err(&client->dev, "get resolution fail\n");
+               mutex_unlock(&dev->input_lock);
+               return -EINVAL;
+       }
+
+       ret = startup(sd);
+       if (ret) {
+               int i = 0;
+               dev_err(&client->dev, "ov5693 startup err, retry to power up\n");
+               for (i = 0; i < OV5693_POWER_UP_RETRY_NUM; i++) {
+                       dev_err(&client->dev,
+                               "ov5693 retry to power up %d/%d times, result: ",
+                               i+1, OV5693_POWER_UP_RETRY_NUM);
+                       power_down(sd);
+                       ret = power_up(sd);
+                       if (!ret) {
+                               mutex_unlock(&dev->input_lock);
+                               ov5693_init(sd);
+                               mutex_lock(&dev->input_lock);
+                       } else {
+                               dev_err(&client->dev, "power up failed, continue\n");
+                               continue;
+                       }
+                       ret = startup(sd);
+                       if (ret) {
+                               dev_err(&client->dev, " startup FAILED!\n");
+                       } else {
+                               dev_err(&client->dev, " startup SUCCESS!\n");
+                               break;
+                       }
+               }
+       }
+
+       /*
+        * After sensor settings are set to HW, sometimes stream is started.
+        * This would cause ISP timeout because ISP is not ready to receive
+        * data yet. So add stop streaming here.
+        */
+       ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_SW_STREAM,
+                               OV5693_STOP_STREAMING);
+       if (ret)
+               dev_warn(&client->dev, "ov5693 stream off err\n");
+
+       ret = ov5693_get_intg_factor(client, ov5693_info,
+                                       &ov5693_res[dev->fmt_idx]);
+       if (ret) {
+               dev_err(&client->dev, "failed to get integration_factor\n");
+               goto err;
+       }
+
+       ov5693_info->metadata_width = fmt->width * 10 / 8;
+       ov5693_info->metadata_height = 1;
+       ov5693_info->metadata_effective_width = &ov5693_embedded_effective_size;
+
+err:
+       mutex_unlock(&dev->input_lock);
+       return ret;
+}
+static int ov5693_get_fmt(struct v4l2_subdev *sd,
+                         struct v4l2_subdev_pad_config *cfg,
+                         struct v4l2_subdev_format *format)
+{
+       struct v4l2_mbus_framefmt *fmt = &format->format;
+       struct ov5693_device *dev = to_ov5693_sensor(sd);
+       if (format->pad)
+               return -EINVAL;
+
+       if (!fmt)
+               return -EINVAL;
+
+       fmt->width = ov5693_res[dev->fmt_idx].width;
+       fmt->height = ov5693_res[dev->fmt_idx].height;
+       fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
+
+       return 0;
+}
+
+static int ov5693_detect(struct i2c_client *client)
+{
+       struct i2c_adapter *adapter = client->adapter;
+       u16 high, low;
+       int ret;
+       u16 id;
+       u8 revision;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
+               return -ENODEV;
+
+       ret = ov5693_read_reg(client, OV5693_8BIT,
+                                       OV5693_SC_CMMN_CHIP_ID_H, &high);
+       if (ret) {
+               dev_err(&client->dev, "sensor_id_high = 0x%x\n", high);
+               return -ENODEV;
+       }
+       ret = ov5693_read_reg(client, OV5693_8BIT,
+                                       OV5693_SC_CMMN_CHIP_ID_L, &low);
+       id = ((((u16) high) << 8) | (u16) low);
+
+       if (id != OV5693_ID) {
+               dev_err(&client->dev, "sensor ID error 0x%x\n", id);
+               return -ENODEV;
+       }
+
+       ret = ov5693_read_reg(client, OV5693_8BIT,
+                                       OV5693_SC_CMMN_SUB_ID, &high);
+       revision = (u8) high & 0x0f;
+
+       dev_dbg(&client->dev, "sensor_revision = 0x%x\n", revision);
+       dev_dbg(&client->dev, "detect ov5693 success\n");
+       return 0;
+}
+
+static int ov5693_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct ov5693_device *dev = to_ov5693_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret;
+
+       mutex_lock(&dev->input_lock);
+
+       ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_SW_STREAM,
+                               enable ? OV5693_START_STREAMING :
+                               OV5693_STOP_STREAMING);
+
+       mutex_unlock(&dev->input_lock);
+
+       return ret;
+}
+
+
+static int ov5693_s_config(struct v4l2_subdev *sd,
+                          int irq, void *platform_data)
+{
+       struct ov5693_device *dev = to_ov5693_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       int ret = 0;
+
+       if (platform_data == NULL)
+               return -ENODEV;
+
+       dev->platform_data =
+               (struct camera_sensor_platform_data *)platform_data;
+
+       mutex_lock(&dev->input_lock);
+       /* power off the module, then power on it in future
+        * as first power on by board may not fulfill the
+        * power on sequqence needed by the module
+        */
+       ret = power_down(sd);
+       if (ret) {
+               dev_err(&client->dev, "ov5693 power-off err.\n");
+               goto fail_power_off;
+       }
+
+       ret = power_up(sd);
+       if (ret) {
+               dev_err(&client->dev, "ov5693 power-up err.\n");
+               goto fail_power_on;
+       }
+
+       if (!dev->vcm)
+               dev->vcm = vcm_detect(client);
+
+       ret = dev->platform_data->csi_cfg(sd, 1);
+       if (ret)
+               goto fail_csi_cfg;
+
+       /* config & detect sensor */
+       ret = ov5693_detect(client);
+       if (ret) {
+               dev_err(&client->dev, "ov5693_detect err s_config.\n");
+               goto fail_csi_cfg;
+       }
+
+       dev->otp_data = ov5693_otp_read(sd);
+
+       /* turn off sensor, after probed */
+       ret = power_down(sd);
+       if (ret) {
+               dev_err(&client->dev, "ov5693 power-off err.\n");
+               goto fail_csi_cfg;
+       }
+       mutex_unlock(&dev->input_lock);
+
+       return ret;
+
+fail_csi_cfg:
+       dev->platform_data->csi_cfg(sd, 0);
+fail_power_on:
+       power_down(sd);
+       dev_err(&client->dev, "sensor power-gating failed\n");
+fail_power_off:
+       mutex_unlock(&dev->input_lock);
+       return ret;
+}
+
+static int ov5693_g_parm(struct v4l2_subdev *sd,
+                       struct v4l2_streamparm *param)
+{
+       struct ov5693_device *dev = to_ov5693_sensor(sd);
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (!param)
+               return -EINVAL;
+
+       if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               dev_err(&client->dev,  "unsupported buffer type.\n");
+               return -EINVAL;
+       }
+
+       memset(param, 0, sizeof(*param));
+       param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+       if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) {
+               param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+               param->parm.capture.timeperframe.numerator = 1;
+               param->parm.capture.capturemode = dev->run_mode;
+               param->parm.capture.timeperframe.denominator =
+                       ov5693_res[dev->fmt_idx].fps;
+       }
+       return 0;
+}
+
+static int ov5693_s_parm(struct v4l2_subdev *sd,
+                       struct v4l2_streamparm *param)
+{
+       struct ov5693_device *dev = to_ov5693_sensor(sd);
+       dev->run_mode = param->parm.capture.capturemode;
+
+       mutex_lock(&dev->input_lock);
+       switch (dev->run_mode) {
+       case CI_MODE_VIDEO:
+               ov5693_res = ov5693_res_video;
+               N_RES = N_RES_VIDEO;
+               break;
+       case CI_MODE_STILL_CAPTURE:
+               ov5693_res = ov5693_res_still;
+               N_RES = N_RES_STILL;
+               break;
+       default:
+               ov5693_res = ov5693_res_preview;
+               N_RES = N_RES_PREVIEW;
+       }
+       mutex_unlock(&dev->input_lock);
+       return 0;
+}
+
+static int ov5693_g_frame_interval(struct v4l2_subdev *sd,
+                                  struct v4l2_subdev_frame_interval *interval)
+{
+       struct ov5693_device *dev = to_ov5693_sensor(sd);
+
+       interval->interval.numerator = 1;
+       interval->interval.denominator = ov5693_res[dev->fmt_idx].fps;
+
+       return 0;
+}
+
+static int ov5693_enum_mbus_code(struct v4l2_subdev *sd,
+                                struct v4l2_subdev_pad_config *cfg,
+                                struct v4l2_subdev_mbus_code_enum *code)
+{
+       if (code->index >= MAX_FMTS)
+               return -EINVAL;
+
+       code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
+       return 0;
+}
+
+static int ov5693_enum_frame_size(struct v4l2_subdev *sd,
+                                 struct v4l2_subdev_pad_config *cfg,
+                                 struct v4l2_subdev_frame_size_enum *fse)
+{
+       int index = fse->index;
+
+       if (index >= N_RES)
+               return -EINVAL;
+
+       fse->min_width = ov5693_res[index].width;
+       fse->min_height = ov5693_res[index].height;
+       fse->max_width = ov5693_res[index].width;
+       fse->max_height = ov5693_res[index].height;
+
+       return 0;
+
+}
+
+static const struct v4l2_subdev_video_ops ov5693_video_ops = {
+       .s_stream = ov5693_s_stream,
+       .g_parm = ov5693_g_parm,
+       .s_parm = ov5693_s_parm,
+       .g_frame_interval = ov5693_g_frame_interval,
+};
+
+static const struct v4l2_subdev_core_ops ov5693_core_ops = {
+       .s_power = ov5693_s_power,
+       .ioctl = ov5693_ioctl,
+};
+
+static const struct v4l2_subdev_pad_ops ov5693_pad_ops = {
+       .enum_mbus_code = ov5693_enum_mbus_code,
+       .enum_frame_size = ov5693_enum_frame_size,
+       .get_fmt = ov5693_get_fmt,
+       .set_fmt = ov5693_set_fmt,
+};
+
+static const struct v4l2_subdev_ops ov5693_ops = {
+       .core = &ov5693_core_ops,
+       .video = &ov5693_video_ops,
+       .pad = &ov5693_pad_ops,
+};
+
+static int ov5693_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct ov5693_device *dev = to_ov5693_sensor(sd);
+       dev_dbg(&client->dev, "ov5693_remove...\n");
+
+       dev->platform_data->csi_cfg(sd, 0);
+
+       v4l2_device_unregister_subdev(sd);
+
+       atomisp_gmin_remove_subdev(sd);
+
+       media_entity_cleanup(&dev->sd.entity);
+       v4l2_ctrl_handler_free(&dev->ctrl_handler);
+       kfree(dev);
+
+       return 0;
+}
+
+static int ov5693_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct ov5693_device *dev;
+       int i2c;
+       int ret = 0;
+       void *pdata = client->dev.platform_data;
+       struct acpi_device *adev;
+       unsigned int i;
+
+       /* Firmware workaround: Some modules use a "secondary default"
+        * address of 0x10 which doesn't appear on schematics, and
+        * some BIOS versions haven't gotten the memo.  Work around
+        * via config. */
+       i2c = gmin_get_var_int(&client->dev, "I2CAddr", -1);
+       if (i2c != -1) {
+               dev_info(&client->dev,
+               "Overriding firmware-provided I2C address (0x%x) with 0x%x\n",
+                        client->addr, i2c);
+               client->addr = i2c;
+       }
+
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev) {
+               dev_err(&client->dev, "out of memory\n");
+               return -ENOMEM;
+       }
+
+       mutex_init(&dev->input_lock);
+
+       dev->fmt_idx = 0;
+       v4l2_i2c_subdev_init(&(dev->sd), client, &ov5693_ops);
+
+       adev = ACPI_COMPANION(&client->dev);
+       if (adev) {
+               adev->power.flags.power_resources = 0;
+               pdata = gmin_camera_platform_data(&dev->sd,
+                                                 ATOMISP_INPUT_FORMAT_RAW_10,
+                                                 atomisp_bayer_order_bggr);
+       }
+
+       if (!pdata)
+               goto out_free;
+
+       ret = ov5693_s_config(&dev->sd, client->irq, pdata);
+       if (ret)
+               goto out_free;
+
+       ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA);
+       if (ret)
+               goto out_free;
+
+       dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+       dev->pad.flags = MEDIA_PAD_FL_SOURCE;
+       dev->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
+       dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+       ret =
+           v4l2_ctrl_handler_init(&dev->ctrl_handler,
+                                  ARRAY_SIZE(ov5693_controls));
+       if (ret) {
+               ov5693_remove(client);
+               return ret;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(ov5693_controls); i++)
+               v4l2_ctrl_new_custom(&dev->ctrl_handler, &ov5693_controls[i],
+                                    NULL);
+
+       if (dev->ctrl_handler.error) {
+               ov5693_remove(client);
+               return dev->ctrl_handler.error;
+       }
+
+       /* Use same lock for controls as for everything else. */
+       dev->ctrl_handler.lock = &dev->input_lock;
+       dev->sd.ctrl_handler = &dev->ctrl_handler;
+
+       ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad);
+       if (ret)
+               ov5693_remove(client);
+
+       return ret;
+out_free:
+       v4l2_device_unregister_subdev(&dev->sd);
+       kfree(dev);
+       return ret;
+}
+
+MODULE_DEVICE_TABLE(i2c, ov5693_id);
+
+static const struct acpi_device_id ov5693_acpi_match[] = {
+       {"INT33BE"},
+       {},
+};
+MODULE_DEVICE_TABLE(acpi, ov5693_acpi_match);
+
+static struct i2c_driver ov5693_driver = {
+       .driver = {
+               .name = OV5693_NAME,
+               .acpi_match_table = ACPI_PTR(ov5693_acpi_match),
+       },
+       .probe = ov5693_probe,
+       .remove = ov5693_remove,
+       .id_table = ov5693_id,
+};
+
+static int init_ov5693(void)
+{
+       return i2c_add_driver(&ov5693_driver);
+}
+
+static void exit_ov5693(void)
+{
+
+       i2c_del_driver(&ov5693_driver);
+}
+
+module_init(init_ov5693);
+module_exit(exit_ov5693);
+
+MODULE_DESCRIPTION("A low-level driver for OmniVision 5693 sensors");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/media/atomisp/i2c/ov5693/ov5693.c b/drivers/staging/media/atomisp/i2c/ov5693/ov5693.c
deleted file mode 100644 (file)
index 2195011..0000000
+++ /dev/null
@@ -1,2059 +0,0 @@
-/*
- * Support for OmniVision OV5693 1080p HD camera sensor.
- *
- * Copyright (c) 2013 Intel Corporation. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/kmod.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/gpio.h>
-#include <linux/moduleparam.h>
-#include <media/v4l2-device.h>
-#include <linux/io.h>
-#include <linux/acpi.h>
-#include "../../include/linux/atomisp_gmin_platform.h"
-
-#include "ov5693.h"
-#include "ad5823.h"
-
-#define __cci_delay(t) \
-       do { \
-               if ((t) < 10) { \
-                       usleep_range((t) * 1000, ((t) + 1) * 1000); \
-               } else { \
-                       msleep((t)); \
-               } \
-       } while (0)
-
-/* Value 30ms reached through experimentation on byt ecs.
- * The DS specifies a much lower value but when using a smaller value
- * the I2C bus sometimes locks up permanently when starting the camera.
- * This issue could not be reproduced on cht, so we can reduce the
- * delay value to a lower value when insmod.
- */
-static uint up_delay = 30;
-module_param(up_delay, uint, 0644);
-MODULE_PARM_DESC(up_delay, "Delay prior to the first CCI transaction for ov5693");
-
-static int vcm_ad_i2c_wr8(struct i2c_client *client, u8 reg, u8 val)
-{
-       int err;
-       struct i2c_msg msg;
-       u8 buf[2];
-
-       buf[0] = reg;
-       buf[1] = val;
-
-       msg.addr = VCM_ADDR;
-       msg.flags = 0;
-       msg.len = 2;
-       msg.buf = &buf[0];
-
-       err = i2c_transfer(client->adapter, &msg, 1);
-       if (err != 1) {
-               dev_err(&client->dev, "%s: vcm i2c fail, err code = %d\n",
-                       __func__, err);
-               return -EIO;
-       }
-       return 0;
-}
-
-static int ad5823_i2c_write(struct i2c_client *client, u8 reg, u8 val)
-{
-       struct i2c_msg msg;
-       u8 buf[2];
-       buf[0] = reg;
-       buf[1] = val;
-       msg.addr = AD5823_VCM_ADDR;
-       msg.flags = 0;
-       msg.len = 0x02;
-       msg.buf = &buf[0];
-
-       if (i2c_transfer(client->adapter, &msg, 1) != 1)
-               return -EIO;
-       return 0;
-}
-
-static int ad5823_i2c_read(struct i2c_client *client, u8 reg, u8 *val)
-{
-       struct i2c_msg msg[2];
-       u8 buf[2];
-       buf[0] = reg;
-       buf[1] = 0;
-
-       msg[0].addr = AD5823_VCM_ADDR;
-       msg[0].flags = 0;
-       msg[0].len = 0x01;
-       msg[0].buf = &buf[0];
-
-       msg[1].addr = 0x0c;
-       msg[1].flags = I2C_M_RD;
-       msg[1].len = 0x01;
-       msg[1].buf = &buf[1];
-       *val = 0;
-       if (i2c_transfer(client->adapter, msg, 2) != 2)
-               return -EIO;
-       *val = buf[1];
-       return 0;
-}
-
-
-static const uint32_t ov5693_embedded_effective_size = 28;
-
-/* i2c read/write stuff */
-static int ov5693_read_reg(struct i2c_client *client,
-                          u16 data_length, u16 reg, u16 *val)
-{
-       int err;
-       struct i2c_msg msg[2];
-       unsigned char data[6];
-
-       if (!client->adapter) {
-               dev_err(&client->dev, "%s error, no client->adapter\n",
-                       __func__);
-               return -ENODEV;
-       }
-
-       if (data_length != OV5693_8BIT && data_length != OV5693_16BIT
-                                       && data_length != OV5693_32BIT) {
-               dev_err(&client->dev, "%s error, invalid data length\n",
-                       __func__);
-               return -EINVAL;
-       }
-
-       memset(msg, 0, sizeof(msg));
-
-       msg[0].addr = client->addr;
-       msg[0].flags = 0;
-       msg[0].len = I2C_MSG_LENGTH;
-       msg[0].buf = data;
-
-       /* high byte goes out first */
-       data[0] = (u8)(reg >> 8);
-       data[1] = (u8)(reg & 0xff);
-
-       msg[1].addr = client->addr;
-       msg[1].len = data_length;
-       msg[1].flags = I2C_M_RD;
-       msg[1].buf = data;
-
-       err = i2c_transfer(client->adapter, msg, 2);
-       if (err != 2) {
-               if (err >= 0)
-                       err = -EIO;
-               dev_err(&client->dev,
-                       "read from offset 0x%x error %d", reg, err);
-               return err;
-       }
-
-       *val = 0;
-       /* high byte comes first */
-       if (data_length == OV5693_8BIT)
-               *val = (u8)data[0];
-       else if (data_length == OV5693_16BIT)
-               *val = be16_to_cpu(*(u16 *)&data[0]);
-       else
-               *val = be32_to_cpu(*(u32 *)&data[0]);
-
-       return 0;
-}
-
-static int ov5693_i2c_write(struct i2c_client *client, u16 len, u8 *data)
-{
-       struct i2c_msg msg;
-       const int num_msg = 1;
-       int ret;
-
-       msg.addr = client->addr;
-       msg.flags = 0;
-       msg.len = len;
-       msg.buf = data;
-       ret = i2c_transfer(client->adapter, &msg, 1);
-
-       return ret == num_msg ? 0 : -EIO;
-}
-
-static int vcm_dw_i2c_write(struct i2c_client *client, u16 data)
-{
-       struct i2c_msg msg;
-       const int num_msg = 1;
-       int ret;
-       u16 val;
-
-       val = cpu_to_be16(data);
-       msg.addr = VCM_ADDR;
-       msg.flags = 0;
-       msg.len = OV5693_16BIT;
-       msg.buf = (u8 *)&val;
-
-       ret = i2c_transfer(client->adapter, &msg, 1);
-
-       return ret == num_msg ? 0 : -EIO;
-}
-
-/* Theory: per datasheet, the two VCMs both allow for a 2-byte read.
- * The DW9714 doesn't actually specify what this does (it has a
- * two-byte write-only protocol, but specifies the read sequence as
- * legal), but it returns the same data (zeroes) always, after an
- * undocumented initial NAK.  The AD5823 has a one-byte address
- * register to which all writes go, and subsequent reads will cycle
- * through the 8 bytes of registers.  Notably, the default values (the
- * device is always power-cycled affirmatively, so we can rely on
- * these) in AD5823 are not pairwise repetitions of the same 16 bit
- * word.  So all we have to do is sequentially read two bytes at a
- * time and see if we detect a difference in any of the first four
- * pairs.  */
-static int vcm_detect(struct i2c_client *client)
-{
-       int i, ret;
-       struct i2c_msg msg;
-       u16 data0 = 0, data;
-       for (i = 0; i < 4; i++) {
-               msg.addr = VCM_ADDR;
-               msg.flags = I2C_M_RD;
-               msg.len = sizeof(data);
-               msg.buf = (u8 *)&data;
-               ret = i2c_transfer(client->adapter, &msg, 1);
-
-               /* DW9714 always fails the first read and returns
-                * zeroes for subsequent ones */
-               if (i == 0 && ret == -EREMOTEIO) {
-                       data0 = 0;
-                       continue;
-               }
-
-               if (i == 0)
-                       data0 = data;
-
-               if (data != data0)
-                       return VCM_AD5823;
-       }
-       return ret == 1 ? VCM_DW9714 : ret;
-}
-
-static int ov5693_write_reg(struct i2c_client *client, u16 data_length,
-                                                       u16 reg, u16 val)
-{
-       int ret;
-       unsigned char data[4] = {0};
-       u16 *wreg = (u16 *)data;
-       const u16 len = data_length + sizeof(u16); /* 16-bit address + data */
-
-       if (data_length != OV5693_8BIT && data_length != OV5693_16BIT) {
-               dev_err(&client->dev,
-                       "%s error, invalid data_length\n", __func__);
-               return -EINVAL;
-       }
-
-       /* high byte goes out first */
-       *wreg = cpu_to_be16(reg);
-
-       if (data_length == OV5693_8BIT) {
-               data[2] = (u8)(val);
-       } else {
-               /* OV5693_16BIT */
-               u16 *wdata = (u16 *)&data[2];
-               *wdata = cpu_to_be16(val);
-       }
-
-       ret = ov5693_i2c_write(client, len, data);
-       if (ret)
-               dev_err(&client->dev,
-                       "write error: wrote 0x%x to offset 0x%x error %d",
-                       val, reg, ret);
-
-       return ret;
-}
-
-/*
- * ov5693_write_reg_array - Initializes a list of OV5693 registers
- * @client: i2c driver client structure
- * @reglist: list of registers to be written
- *
- * This function initializes a list of registers. When consecutive addresses
- * are found in a row on the list, this function creates a buffer and sends
- * consecutive data in a single i2c_transfer().
- *
- * __ov5693_flush_reg_array, __ov5693_buf_reg_array() and
- * __ov5693_write_reg_is_consecutive() are internal functions to
- * ov5693_write_reg_array_fast() and should be not used anywhere else.
- *
- */
-
-static int __ov5693_flush_reg_array(struct i2c_client *client,
-                                   struct ov5693_write_ctrl *ctrl)
-{
-       u16 size;
-
-       if (ctrl->index == 0)
-               return 0;
-
-       size = sizeof(u16) + ctrl->index; /* 16-bit address + data */
-       ctrl->buffer.addr = cpu_to_be16(ctrl->buffer.addr);
-       ctrl->index = 0;
-
-       return ov5693_i2c_write(client, size, (u8 *)&ctrl->buffer);
-}
-
-static int __ov5693_buf_reg_array(struct i2c_client *client,
-                                 struct ov5693_write_ctrl *ctrl,
-                                 const struct ov5693_reg *next)
-{
-       int size;
-       u16 *data16;
-
-       switch (next->type) {
-       case OV5693_8BIT:
-               size = 1;
-               ctrl->buffer.data[ctrl->index] = (u8)next->val;
-               break;
-       case OV5693_16BIT:
-               size = 2;
-               data16 = (u16 *)&ctrl->buffer.data[ctrl->index];
-               *data16 = cpu_to_be16((u16)next->val);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       /* When first item is added, we need to store its starting address */
-       if (ctrl->index == 0)
-               ctrl->buffer.addr = next->reg;
-
-       ctrl->index += size;
-
-       /*
-        * Buffer cannot guarantee free space for u32? Better flush it to avoid
-        * possible lack of memory for next item.
-        */
-       if (ctrl->index + sizeof(u16) >= OV5693_MAX_WRITE_BUF_SIZE)
-               return __ov5693_flush_reg_array(client, ctrl);
-
-       return 0;
-}
-
-static int __ov5693_write_reg_is_consecutive(struct i2c_client *client,
-                                            struct ov5693_write_ctrl *ctrl,
-                                            const struct ov5693_reg *next)
-{
-       if (ctrl->index == 0)
-               return 1;
-
-       return ctrl->buffer.addr + ctrl->index == next->reg;
-}
-
-static int ov5693_write_reg_array(struct i2c_client *client,
-                                 const struct ov5693_reg *reglist)
-{
-       const struct ov5693_reg *next = reglist;
-       struct ov5693_write_ctrl ctrl;
-       int err;
-
-       ctrl.index = 0;
-       for (; next->type != OV5693_TOK_TERM; next++) {
-               switch (next->type & OV5693_TOK_MASK) {
-               case OV5693_TOK_DELAY:
-                       err = __ov5693_flush_reg_array(client, &ctrl);
-                       if (err)
-                               return err;
-                       msleep(next->val);
-                       break;
-               default:
-                       /*
-                        * If next address is not consecutive, data needs to be
-                        * flushed before proceed.
-                        */
-                       if (!__ov5693_write_reg_is_consecutive(client, &ctrl,
-                                                               next)) {
-                               err = __ov5693_flush_reg_array(client, &ctrl);
-                       if (err)
-                               return err;
-                       }
-                       err = __ov5693_buf_reg_array(client, &ctrl, next);
-                       if (err) {
-                               dev_err(&client->dev,
-                                       "%s: write error, aborted\n",
-                                       __func__);
-                               return err;
-                       }
-                       break;
-               }
-       }
-
-       return __ov5693_flush_reg_array(client, &ctrl);
-}
-static int ov5693_g_focal(struct v4l2_subdev *sd, s32 *val)
-{
-       *val = (OV5693_FOCAL_LENGTH_NUM << 16) | OV5693_FOCAL_LENGTH_DEM;
-       return 0;
-}
-
-static int ov5693_g_fnumber(struct v4l2_subdev *sd, s32 *val)
-{
-       /*const f number for imx*/
-       *val = (OV5693_F_NUMBER_DEFAULT_NUM << 16) | OV5693_F_NUMBER_DEM;
-       return 0;
-}
-
-static int ov5693_g_fnumber_range(struct v4l2_subdev *sd, s32 *val)
-{
-       *val = (OV5693_F_NUMBER_DEFAULT_NUM << 24) |
-               (OV5693_F_NUMBER_DEM << 16) |
-               (OV5693_F_NUMBER_DEFAULT_NUM << 8) | OV5693_F_NUMBER_DEM;
-       return 0;
-}
-
-static int ov5693_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val)
-{
-       struct ov5693_device *dev = to_ov5693_sensor(sd);
-
-       *val = ov5693_res[dev->fmt_idx].bin_factor_x;
-
-       return 0;
-}
-
-static int ov5693_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val)
-{
-       struct ov5693_device *dev = to_ov5693_sensor(sd);
-
-       *val = ov5693_res[dev->fmt_idx].bin_factor_y;
-
-       return 0;
-}
-
-static int ov5693_get_intg_factor(struct i2c_client *client,
-                               struct camera_mipi_info *info,
-                               const struct ov5693_resolution *res)
-{
-       struct v4l2_subdev *sd = i2c_get_clientdata(client);
-       struct ov5693_device *dev = to_ov5693_sensor(sd);
-       struct atomisp_sensor_mode_data *buf = &info->data;
-       unsigned int pix_clk_freq_hz;
-       u16 reg_val;
-       int ret;
-
-       if (info == NULL)
-               return -EINVAL;
-
-       /* pixel clock */
-       pix_clk_freq_hz = res->pix_clk_freq * 1000000;
-
-       dev->vt_pix_clk_freq_mhz = pix_clk_freq_hz;
-       buf->vt_pix_clk_freq_mhz = pix_clk_freq_hz;
-
-       /* get integration time */
-       buf->coarse_integration_time_min = OV5693_COARSE_INTG_TIME_MIN;
-       buf->coarse_integration_time_max_margin =
-                                       OV5693_COARSE_INTG_TIME_MAX_MARGIN;
-
-       buf->fine_integration_time_min = OV5693_FINE_INTG_TIME_MIN;
-       buf->fine_integration_time_max_margin =
-                                       OV5693_FINE_INTG_TIME_MAX_MARGIN;
-
-       buf->fine_integration_time_def = OV5693_FINE_INTG_TIME_MIN;
-       buf->frame_length_lines = res->lines_per_frame;
-       buf->line_length_pck = res->pixels_per_line;
-       buf->read_mode = res->bin_mode;
-
-       /* get the cropping and output resolution to ISP for this mode. */
-       ret =  ov5693_read_reg(client, OV5693_16BIT,
-                                       OV5693_HORIZONTAL_START_H, &reg_val);
-       if (ret)
-               return ret;
-       buf->crop_horizontal_start = reg_val;
-
-       ret =  ov5693_read_reg(client, OV5693_16BIT,
-                                       OV5693_VERTICAL_START_H, &reg_val);
-       if (ret)
-               return ret;
-       buf->crop_vertical_start = reg_val;
-
-       ret = ov5693_read_reg(client, OV5693_16BIT,
-                                       OV5693_HORIZONTAL_END_H, &reg_val);
-       if (ret)
-               return ret;
-       buf->crop_horizontal_end = reg_val;
-
-       ret = ov5693_read_reg(client, OV5693_16BIT,
-                                       OV5693_VERTICAL_END_H, &reg_val);
-       if (ret)
-               return ret;
-       buf->crop_vertical_end = reg_val;
-
-       ret = ov5693_read_reg(client, OV5693_16BIT,
-                               OV5693_HORIZONTAL_OUTPUT_SIZE_H, &reg_val);
-       if (ret)
-               return ret;
-       buf->output_width = reg_val;
-
-       ret = ov5693_read_reg(client, OV5693_16BIT,
-                               OV5693_VERTICAL_OUTPUT_SIZE_H, &reg_val);
-       if (ret)
-               return ret;
-       buf->output_height = reg_val;
-
-       buf->binning_factor_x = res->bin_factor_x ?
-                                       res->bin_factor_x : 1;
-       buf->binning_factor_y = res->bin_factor_y ?
-                                       res->bin_factor_y : 1;
-       return 0;
-}
-
-static long __ov5693_set_exposure(struct v4l2_subdev *sd, int coarse_itg,
-                                int gain, int digitgain)
-
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct ov5693_device *dev = to_ov5693_sensor(sd);
-       u16 vts, hts;
-       int ret, exp_val;
-
-       hts = ov5693_res[dev->fmt_idx].pixels_per_line;
-       vts = ov5693_res[dev->fmt_idx].lines_per_frame;
-       /*If coarse_itg is larger than 1<<15, can not write to reg directly.
-         The way is to write coarse_itg/2 to the reg, meanwhile write 2*hts
-         to the reg. */
-       if (coarse_itg > (1 << 15)) {
-               hts = hts * 2;
-               coarse_itg = (int)coarse_itg / 2;
-       }
-       /* group hold */
-       ret = ov5693_write_reg(client, OV5693_8BIT,
-                               OV5693_GROUP_ACCESS, 0x00);
-       if (ret) {
-               dev_err(&client->dev, "%s: write %x error, aborted\n",
-                       __func__, OV5693_GROUP_ACCESS);
-               return ret;
-       }
-
-       ret = ov5693_write_reg(client, OV5693_8BIT,
-                               OV5693_TIMING_HTS_H, (hts >> 8) & 0xFF);
-       if (ret) {
-               dev_err(&client->dev, "%s: write %x error, aborted\n",
-                       __func__, OV5693_TIMING_HTS_H);
-               return ret;
-       }
-
-       ret = ov5693_write_reg(client, OV5693_8BIT,
-                               OV5693_TIMING_HTS_L, hts & 0xFF);
-       if (ret) {
-               dev_err(&client->dev, "%s: write %x error, aborted\n",
-                       __func__, OV5693_TIMING_HTS_L);
-               return ret;
-       }
-       /* Increase the VTS to match exposure + MARGIN */
-       if (coarse_itg > vts - OV5693_INTEGRATION_TIME_MARGIN)
-               vts = (u16) coarse_itg + OV5693_INTEGRATION_TIME_MARGIN;
-
-       ret = ov5693_write_reg(client, OV5693_8BIT,
-                               OV5693_TIMING_VTS_H, (vts >> 8) & 0xFF);
-       if (ret) {
-               dev_err(&client->dev, "%s: write %x error, aborted\n",
-                       __func__, OV5693_TIMING_VTS_H);
-               return ret;
-       }
-
-       ret = ov5693_write_reg(client, OV5693_8BIT,
-                                       OV5693_TIMING_VTS_L, vts & 0xFF);
-       if (ret) {
-               dev_err(&client->dev, "%s: write %x error, aborted\n",
-                       __func__, OV5693_TIMING_VTS_L);
-               return ret;
-       }
-
-       /* set exposure */
-
-       /* Lower four bit should be 0*/
-       exp_val = coarse_itg << 4;
-       ret = ov5693_write_reg(client, OV5693_8BIT,
-                              OV5693_EXPOSURE_L, exp_val & 0xFF);
-       if (ret) {
-               dev_err(&client->dev, "%s: write %x error, aborted\n",
-                       __func__, OV5693_EXPOSURE_L);
-               return ret;
-       }
-
-       ret = ov5693_write_reg(client, OV5693_8BIT,
-                              OV5693_EXPOSURE_M, (exp_val >> 8) & 0xFF);
-       if (ret) {
-               dev_err(&client->dev, "%s: write %x error, aborted\n",
-                       __func__, OV5693_EXPOSURE_M);
-               return ret;
-       }
-
-       ret = ov5693_write_reg(client, OV5693_8BIT,
-                              OV5693_EXPOSURE_H, (exp_val >> 16) & 0x0F);
-       if (ret) {
-               dev_err(&client->dev, "%s: write %x error, aborted\n",
-                       __func__, OV5693_EXPOSURE_H);
-               return ret;
-       }
-
-       /* Analog gain */
-       ret = ov5693_write_reg(client, OV5693_8BIT,
-                               OV5693_AGC_L, gain & 0xff);
-       if (ret) {
-               dev_err(&client->dev, "%s: write %x error, aborted\n",
-                       __func__, OV5693_AGC_L);
-               return ret;
-       }
-
-       ret = ov5693_write_reg(client, OV5693_8BIT,
-                               OV5693_AGC_H, (gain >> 8) & 0xff);
-       if (ret) {
-               dev_err(&client->dev, "%s: write %x error, aborted\n",
-                       __func__, OV5693_AGC_H);
-               return ret;
-       }
-
-       /* Digital gain */
-       if (digitgain) {
-               ret = ov5693_write_reg(client, OV5693_16BIT,
-                               OV5693_MWB_RED_GAIN_H, digitgain);
-               if (ret) {
-                       dev_err(&client->dev, "%s: write %x error, aborted\n",
-                               __func__, OV5693_MWB_RED_GAIN_H);
-                       return ret;
-               }
-
-               ret = ov5693_write_reg(client, OV5693_16BIT,
-                               OV5693_MWB_GREEN_GAIN_H, digitgain);
-               if (ret) {
-                       dev_err(&client->dev, "%s: write %x error, aborted\n",
-                               __func__, OV5693_MWB_RED_GAIN_H);
-                       return ret;
-               }
-
-               ret = ov5693_write_reg(client, OV5693_16BIT,
-                               OV5693_MWB_BLUE_GAIN_H, digitgain);
-               if (ret) {
-                       dev_err(&client->dev, "%s: write %x error, aborted\n",
-                               __func__, OV5693_MWB_RED_GAIN_H);
-                       return ret;
-               }
-       }
-
-       /* End group */
-       ret = ov5693_write_reg(client, OV5693_8BIT,
-                               OV5693_GROUP_ACCESS, 0x10);
-       if (ret)
-               return ret;
-
-       /* Delay launch group */
-       ret = ov5693_write_reg(client, OV5693_8BIT,
-                               OV5693_GROUP_ACCESS, 0xa0);
-       if (ret)
-               return ret;
-       return ret;
-}
-
-static int ov5693_set_exposure(struct v4l2_subdev *sd, int exposure,
-       int gain, int digitgain)
-{
-       struct ov5693_device *dev = to_ov5693_sensor(sd);
-       int ret;
-
-       mutex_lock(&dev->input_lock);
-       ret = __ov5693_set_exposure(sd, exposure, gain, digitgain);
-       mutex_unlock(&dev->input_lock);
-
-       return ret;
-}
-
-static long ov5693_s_exposure(struct v4l2_subdev *sd,
-                              struct atomisp_exposure *exposure)
-{
-       u16 coarse_itg = exposure->integration_time[0];
-       u16 analog_gain = exposure->gain[0];
-       u16 digital_gain = exposure->gain[1];
-
-       /* we should not accept the invalid value below */
-       if (analog_gain == 0) {
-               struct i2c_client *client = v4l2_get_subdevdata(sd);
-               v4l2_err(client, "%s: invalid value\n", __func__);
-               return -EINVAL;
-       }
-       return ov5693_set_exposure(sd, coarse_itg, analog_gain, digital_gain);
-}
-
-static int ov5693_read_otp_reg_array(struct i2c_client *client, u16 size,
-                                    u16 addr, u8 *buf)
-{
-       u16 index;
-       int ret;
-       u16 *pVal = NULL;
-
-       for (index = 0; index <= size; index++) {
-               pVal = (u16 *) (buf + index);
-               ret =
-                       ov5693_read_reg(client, OV5693_8BIT, addr + index,
-                                   pVal);
-               if (ret)
-                       return ret;
-       }
-
-       return 0;
-}
-
-static int __ov5693_otp_read(struct v4l2_subdev *sd, u8 *buf)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct ov5693_device *dev = to_ov5693_sensor(sd);
-       int ret;
-       int i;
-       u8 *b = buf;
-       dev->otp_size = 0;
-       for (i = 1; i < OV5693_OTP_BANK_MAX; i++) {
-               /*set bank NO and OTP read mode. */
-               ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_OTP_BANK_REG, (i | 0xc0));   //[7:6] 2'b11 [5:0] bank no
-               if (ret) {
-                       dev_err(&client->dev, "failed to prepare OTP page\n");
-                       return ret;
-               }
-               //pr_debug("write 0x%x->0x%x\n",OV5693_OTP_BANK_REG,(i|0xc0));
-
-               /*enable read */
-               ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_OTP_READ_REG, OV5693_OTP_MODE_READ); // enable :1
-               if (ret) {
-                       dev_err(&client->dev,
-                               "failed to set OTP reading mode page");
-                       return ret;
-               }
-               //pr_debug("write 0x%x->0x%x\n",OV5693_OTP_READ_REG,OV5693_OTP_MODE_READ);
-
-               /* Reading the OTP data array */
-               ret = ov5693_read_otp_reg_array(client, OV5693_OTP_BANK_SIZE,
-                                               OV5693_OTP_START_ADDR,
-                                               b);
-               if (ret) {
-                       dev_err(&client->dev, "failed to read OTP data\n");
-                       return ret;
-               }
-
-               //pr_debug("BANK[%2d] %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", i, *b, *(b+1), *(b+2), *(b+3), *(b+4), *(b+5), *(b+6), *(b+7), *(b+8), *(b+9), *(b+10), *(b+11), *(b+12), *(b+13), *(b+14), *(b+15));
-
-               //Intel OTP map, try to read 320byts first.
-               if (21 == i) {
-                       if ((*b) == 0) {
-                               dev->otp_size = 320;
-                               break;
-                       } else {
-                               b = buf;
-                               continue;
-                       }
-               } else if (24 == i) {           //if the first 320bytes data doesn't not exist, try to read the next 32bytes data.
-                       if ((*b) == 0) {
-                               dev->otp_size = 32;
-                               break;
-               } else {
-                               b = buf;
-                               continue;
-                       }
-               } else if (27 == i) {           //if the prvious 32bytes data doesn't exist, try to read the next 32bytes data again.
-                       if ((*b) == 0) {
-                               dev->otp_size = 32;
-                               break;
-                       } else {
-                               dev->otp_size = 0;      // no OTP data.
-                               break;
-                       }
-               }
-
-               b = b + OV5693_OTP_BANK_SIZE;
-       }
-       return 0;
-}
-
-/*
- * Read otp data and store it into a kmalloced buffer.
- * The caller must kfree the buffer when no more needed.
- * @size: set to the size of the returned otp data.
- */
-static void *ov5693_otp_read(struct v4l2_subdev *sd)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       u8 *buf;
-       int ret;
-
-       buf = devm_kzalloc(&client->dev, (OV5693_OTP_DATA_SIZE + 16), GFP_KERNEL);
-       if (!buf)
-               return ERR_PTR(-ENOMEM);
-
-       //otp valid after mipi on and sw stream on
-       ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_FRAME_OFF_NUM, 0x00);
-
-       ret = ov5693_write_reg(client, OV5693_8BIT,
-                              OV5693_SW_STREAM, OV5693_START_STREAMING);
-
-       ret = __ov5693_otp_read(sd, buf);
-
-       //mipi off and sw stream off after otp read
-       ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_FRAME_OFF_NUM, 0x0f);
-
-       ret = ov5693_write_reg(client, OV5693_8BIT,
-                              OV5693_SW_STREAM, OV5693_STOP_STREAMING);
-
-       /* Driver has failed to find valid data */
-       if (ret) {
-               dev_err(&client->dev, "sensor found no valid OTP data\n");
-               return ERR_PTR(ret);
-       }
-
-       return buf;
-}
-
-static int ov5693_g_priv_int_data(struct v4l2_subdev *sd,
-                                 struct v4l2_private_int_data *priv)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct ov5693_device *dev = to_ov5693_sensor(sd);
-       u8 __user *to = priv->data;
-       u32 read_size = priv->size;
-       int ret;
-
-       /* No need to copy data if size is 0 */
-       if (!read_size)
-               goto out;
-
-       if (IS_ERR(dev->otp_data)) {
-               dev_err(&client->dev, "OTP data not available");
-               return PTR_ERR(dev->otp_data);
-       }
-
-       /* Correct read_size value only if bigger than maximum */
-       if (read_size > OV5693_OTP_DATA_SIZE)
-               read_size = OV5693_OTP_DATA_SIZE;
-
-       ret = copy_to_user(to, dev->otp_data, read_size);
-       if (ret) {
-               dev_err(&client->dev, "%s: failed to copy OTP data to user\n",
-                       __func__);
-               return -EFAULT;
-       }
-
-       pr_debug("%s read_size:%d\n", __func__, read_size);
-
-out:
-       /* Return correct size */
-       priv->size = dev->otp_size;
-
-       return 0;
-
-}
-
-static long ov5693_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
-{
-
-       switch (cmd) {
-       case ATOMISP_IOC_S_EXPOSURE:
-               return ov5693_s_exposure(sd, arg);
-       case ATOMISP_IOC_G_SENSOR_PRIV_INT_DATA:
-               return ov5693_g_priv_int_data(sd, arg);
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-
-/* This returns the exposure time being used. This should only be used
-   for filling in EXIF data, not for actual image processing. */
-static int ov5693_q_exposure(struct v4l2_subdev *sd, s32 *value)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       u16 reg_v, reg_v2;
-       int ret;
-
-       /* get exposure */
-       ret = ov5693_read_reg(client, OV5693_8BIT,
-                                       OV5693_EXPOSURE_L,
-                                       &reg_v);
-       if (ret)
-               goto err;
-
-       ret = ov5693_read_reg(client, OV5693_8BIT,
-                                       OV5693_EXPOSURE_M,
-                                       &reg_v2);
-       if (ret)
-               goto err;
-
-       reg_v += reg_v2 << 8;
-       ret = ov5693_read_reg(client, OV5693_8BIT,
-                                       OV5693_EXPOSURE_H,
-                                       &reg_v2);
-       if (ret)
-               goto err;
-
-       *value = reg_v + (((u32)reg_v2 << 16));
-err:
-       return ret;
-}
-
-static int ad5823_t_focus_vcm(struct v4l2_subdev *sd, u16 val)
-{
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret = -EINVAL;
-       u8 vcm_code;
-
-       ret = ad5823_i2c_read(client, AD5823_REG_VCM_CODE_MSB, &vcm_code);
-       if (ret)
-               return ret;
-
-       /* set reg VCM_CODE_MSB Bit[1:0] */
-       vcm_code = (vcm_code & VCM_CODE_MSB_MASK) |
-               ((val >> 8) & ~VCM_CODE_MSB_MASK);
-       ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_MSB, vcm_code);
-       if (ret)
-               return ret;
-
-       /* set reg VCM_CODE_LSB Bit[7:0] */
-       ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_LSB, (val & 0xff));
-       if (ret)
-               return ret;
-
-       /* set required vcm move time */
-       vcm_code = AD5823_RESONANCE_PERIOD / AD5823_RESONANCE_COEF
-               - AD5823_HIGH_FREQ_RANGE;
-       ret = ad5823_i2c_write(client, AD5823_REG_VCM_MOVE_TIME, vcm_code);
-
-       return ret;
-}
-
-int ad5823_t_focus_abs(struct v4l2_subdev *sd, s32 value)
-{
-       value = min(value, AD5823_MAX_FOCUS_POS);
-       return ad5823_t_focus_vcm(sd, value);
-}
-
-static int ov5693_t_focus_abs(struct v4l2_subdev *sd, s32 value)
-{
-       struct ov5693_device *dev = to_ov5693_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret = 0;
-
-       dev_dbg(&client->dev, "%s: FOCUS_POS: 0x%x\n", __func__, value);
-       value = clamp(value, 0, OV5693_VCM_MAX_FOCUS_POS);
-       if (dev->vcm == VCM_DW9714) {
-               if (dev->vcm_update) {
-                       ret = vcm_dw_i2c_write(client, VCM_PROTECTION_OFF);
-                       if (ret)
-                               return ret;
-                       ret = vcm_dw_i2c_write(client, DIRECT_VCM);
-                       if (ret)
-                               return ret;
-                       ret = vcm_dw_i2c_write(client, VCM_PROTECTION_ON);
-                       if (ret)
-                               return ret;
-                       dev->vcm_update = false;
-               }
-               ret = vcm_dw_i2c_write(client,
-                                      vcm_val(value, VCM_DEFAULT_S));
-       } else if (dev->vcm == VCM_AD5823) {
-               ad5823_t_focus_abs(sd, value);
-       }
-       if (ret == 0) {
-               dev->number_of_steps = value - dev->focus;
-               dev->focus = value;
-               getnstimeofday(&(dev->timestamp_t_focus_abs));
-       } else
-               dev_err(&client->dev,
-                       "%s: i2c failed. ret %d\n", __func__, ret);
-
-       return ret;
-}
-
-static int ov5693_t_focus_rel(struct v4l2_subdev *sd, s32 value)
-{
-       struct ov5693_device *dev = to_ov5693_sensor(sd);
-       return ov5693_t_focus_abs(sd, dev->focus + value);
-}
-
-#define DELAY_PER_STEP_NS      1000000
-#define DELAY_MAX_PER_STEP_NS  (1000000 * 1023)
-static int ov5693_q_focus_status(struct v4l2_subdev *sd, s32 *value)
-{
-       u32 status = 0;
-       struct ov5693_device *dev = to_ov5693_sensor(sd);
-       struct timespec temptime;
-       const struct timespec timedelay = {
-               0,
-               min((u32)abs(dev->number_of_steps) * DELAY_PER_STEP_NS,
-               (u32)DELAY_MAX_PER_STEP_NS),
-       };
-
-       getnstimeofday(&temptime);
-       temptime = timespec_sub(temptime, (dev->timestamp_t_focus_abs));
-       if (timespec_compare(&temptime, &timedelay) <= 0) {
-               status |= ATOMISP_FOCUS_STATUS_MOVING;
-               status |= ATOMISP_FOCUS_HP_IN_PROGRESS;
-       } else {
-               status |= ATOMISP_FOCUS_STATUS_ACCEPTS_NEW_MOVE;
-               status |= ATOMISP_FOCUS_HP_COMPLETE;
-       }
-
-       *value = status;
-
-       return 0;
-}
-
-static int ov5693_q_focus_abs(struct v4l2_subdev *sd, s32 *value)
-{
-       struct ov5693_device *dev = to_ov5693_sensor(sd);
-       s32 val;
-
-       ov5693_q_focus_status(sd, &val);
-
-       if (val & ATOMISP_FOCUS_STATUS_MOVING)
-               *value  = dev->focus - dev->number_of_steps;
-       else
-               *value  = dev->focus;
-
-       return 0;
-}
-
-static int ov5693_t_vcm_slew(struct v4l2_subdev *sd, s32 value)
-{
-       struct ov5693_device *dev = to_ov5693_sensor(sd);
-       dev->number_of_steps = value;
-       dev->vcm_update = true;
-       return 0;
-}
-
-static int ov5693_t_vcm_timing(struct v4l2_subdev *sd, s32 value)
-{
-       struct ov5693_device *dev = to_ov5693_sensor(sd);
-       dev->number_of_steps = value;
-       dev->vcm_update = true;
-       return 0;
-}
-
-static int ov5693_s_ctrl(struct v4l2_ctrl *ctrl)
-{
-       struct ov5693_device *dev =
-           container_of(ctrl->handler, struct ov5693_device, ctrl_handler);
-       struct i2c_client *client = v4l2_get_subdevdata(&dev->sd);
-       int ret = 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_FOCUS_ABSOLUTE:
-               dev_dbg(&client->dev, "%s: CID_FOCUS_ABSOLUTE:%d.\n",
-                       __func__, ctrl->val);
-               ret = ov5693_t_focus_abs(&dev->sd, ctrl->val);
-               break;
-       case V4L2_CID_FOCUS_RELATIVE:
-               dev_dbg(&client->dev, "%s: CID_FOCUS_RELATIVE:%d.\n",
-                       __func__, ctrl->val);
-               ret = ov5693_t_focus_rel(&dev->sd, ctrl->val);
-               break;
-       case V4L2_CID_VCM_SLEW:
-               ret = ov5693_t_vcm_slew(&dev->sd, ctrl->val);
-               break;
-       case V4L2_CID_VCM_TIMEING:
-               ret = ov5693_t_vcm_timing(&dev->sd, ctrl->val);
-               break;
-       default:
-               ret = -EINVAL;
-       }
-       return ret;
-}
-
-static int ov5693_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
-{
-       struct ov5693_device *dev =
-           container_of(ctrl->handler, struct ov5693_device, ctrl_handler);
-       int ret = 0;
-
-       switch (ctrl->id) {
-       case V4L2_CID_EXPOSURE_ABSOLUTE:
-               ret = ov5693_q_exposure(&dev->sd, &ctrl->val);
-               break;
-       case V4L2_CID_FOCAL_ABSOLUTE:
-               ret = ov5693_g_focal(&dev->sd, &ctrl->val);
-               break;
-       case V4L2_CID_FNUMBER_ABSOLUTE:
-               ret = ov5693_g_fnumber(&dev->sd, &ctrl->val);
-               break;
-       case V4L2_CID_FNUMBER_RANGE:
-               ret = ov5693_g_fnumber_range(&dev->sd, &ctrl->val);
-               break;
-       case V4L2_CID_FOCUS_ABSOLUTE:
-               ret = ov5693_q_focus_abs(&dev->sd, &ctrl->val);
-               break;
-       case V4L2_CID_FOCUS_STATUS:
-               ret = ov5693_q_focus_status(&dev->sd, &ctrl->val);
-               break;
-       case V4L2_CID_BIN_FACTOR_HORZ:
-               ret = ov5693_g_bin_factor_x(&dev->sd, &ctrl->val);
-               break;
-       case V4L2_CID_BIN_FACTOR_VERT:
-               ret = ov5693_g_bin_factor_y(&dev->sd, &ctrl->val);
-               break;
-       default:
-               ret = -EINVAL;
-       }
-
-       return ret;
-}
-
-static const struct v4l2_ctrl_ops ctrl_ops = {
-       .s_ctrl = ov5693_s_ctrl,
-       .g_volatile_ctrl = ov5693_g_volatile_ctrl
-};
-
-struct v4l2_ctrl_config ov5693_controls[] = {
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_EXPOSURE_ABSOLUTE,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .name = "exposure",
-        .min = 0x0,
-        .max = 0xffff,
-        .step = 0x01,
-        .def = 0x00,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_FOCAL_ABSOLUTE,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .name = "focal length",
-        .min = OV5693_FOCAL_LENGTH_DEFAULT,
-        .max = OV5693_FOCAL_LENGTH_DEFAULT,
-        .step = 0x01,
-        .def = OV5693_FOCAL_LENGTH_DEFAULT,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_FNUMBER_ABSOLUTE,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .name = "f-number",
-        .min = OV5693_F_NUMBER_DEFAULT,
-        .max = OV5693_F_NUMBER_DEFAULT,
-        .step = 0x01,
-        .def = OV5693_F_NUMBER_DEFAULT,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_FNUMBER_RANGE,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .name = "f-number range",
-        .min = OV5693_F_NUMBER_RANGE,
-        .max = OV5693_F_NUMBER_RANGE,
-        .step = 0x01,
-        .def = OV5693_F_NUMBER_RANGE,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_FOCUS_ABSOLUTE,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .name = "focus move absolute",
-        .min = 0,
-        .max = OV5693_VCM_MAX_FOCUS_POS,
-        .step = 1,
-        .def = 0,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_FOCUS_RELATIVE,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .name = "focus move relative",
-        .min = OV5693_VCM_MAX_FOCUS_NEG,
-        .max = OV5693_VCM_MAX_FOCUS_POS,
-        .step = 1,
-        .def = 0,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_FOCUS_STATUS,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .name = "focus status",
-        .min = 0,
-        .max = 100,            /* allow enum to grow in the future */
-        .step = 1,
-        .def = 0,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_VCM_SLEW,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .name = "vcm slew",
-        .min = 0,
-        .max = OV5693_VCM_SLEW_STEP_MAX,
-        .step = 1,
-        .def = 0,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_VCM_TIMEING,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .name = "vcm step time",
-        .min = 0,
-        .max = OV5693_VCM_SLEW_TIME_MAX,
-        .step = 1,
-        .def = 0,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_BIN_FACTOR_HORZ,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .name = "horizontal binning factor",
-        .min = 0,
-        .max = OV5693_BIN_FACTOR_MAX,
-        .step = 1,
-        .def = 0,
-        .flags = 0,
-        },
-       {
-        .ops = &ctrl_ops,
-        .id = V4L2_CID_BIN_FACTOR_VERT,
-        .type = V4L2_CTRL_TYPE_INTEGER,
-        .name = "vertical binning factor",
-        .min = 0,
-        .max = OV5693_BIN_FACTOR_MAX,
-        .step = 1,
-        .def = 0,
-        .flags = 0,
-        },
-};
-
-static int ov5693_init(struct v4l2_subdev *sd)
-{
-       struct ov5693_device *dev = to_ov5693_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret;
-
-       pr_info("%s\n", __func__);
-       mutex_lock(&dev->input_lock);
-       dev->vcm_update = false;
-
-       if (dev->vcm == VCM_AD5823) {
-               ret = vcm_ad_i2c_wr8(client, 0x01, 0x01); /* vcm init test */
-               if (ret)
-                       dev_err(&client->dev,
-                               "vcm reset failed\n");
-               /*change the mode*/
-               ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_MSB,
-                                      AD5823_RING_CTRL_ENABLE);
-               if (ret)
-                       dev_err(&client->dev,
-                               "vcm enable ringing failed\n");
-               ret = ad5823_i2c_write(client, AD5823_REG_MODE,
-                                       AD5823_ARC_RES1);
-               if (ret)
-                       dev_err(&client->dev,
-                               "vcm change mode failed\n");
-       }
-
-       /*change initial focus value for ad5823*/
-       if (dev->vcm == VCM_AD5823) {
-               dev->focus = AD5823_INIT_FOCUS_POS;
-               ov5693_t_focus_abs(sd, AD5823_INIT_FOCUS_POS);
-       } else {
-               dev->focus = 0;
-               ov5693_t_focus_abs(sd, 0);
-       }
-
-       mutex_unlock(&dev->input_lock);
-
-       return 0;
-}
-
-static int power_ctrl(struct v4l2_subdev *sd, bool flag)
-{
-       int ret;
-       struct ov5693_device *dev = to_ov5693_sensor(sd);
-
-       if (!dev || !dev->platform_data)
-               return -ENODEV;
-
-       /* Non-gmin platforms use the legacy callback */
-       if (dev->platform_data->power_ctrl)
-               return dev->platform_data->power_ctrl(sd, flag);
-
-       /* This driver assumes "internal DVDD, PWDNB tied to DOVDD".
-        * In this set up only gpio0 (XSHUTDN) should be available
-        * but in some products (for example ECS) gpio1 (PWDNB) is
-        * also available. If gpio1 is available we emulate it being
-        * tied to DOVDD here. */
-       if (flag) {
-               ret = dev->platform_data->v2p8_ctrl(sd, 1);
-               dev->platform_data->gpio1_ctrl(sd, 1);
-               if (ret == 0) {
-                       ret = dev->platform_data->v1p8_ctrl(sd, 1);
-                       if (ret) {
-                               dev->platform_data->gpio1_ctrl(sd, 0);
-                               ret = dev->platform_data->v2p8_ctrl(sd, 0);
-                       }
-               }
-       } else {
-               dev->platform_data->gpio1_ctrl(sd, 0);
-               ret = dev->platform_data->v1p8_ctrl(sd, 0);
-               ret |= dev->platform_data->v2p8_ctrl(sd, 0);
-       }
-
-       return ret;
-}
-
-static int gpio_ctrl(struct v4l2_subdev *sd, bool flag)
-{
-       struct ov5693_device *dev = to_ov5693_sensor(sd);
-
-       if (!dev || !dev->platform_data)
-               return -ENODEV;
-
-       /* Non-gmin platforms use the legacy callback */
-       if (dev->platform_data->gpio_ctrl)
-               return dev->platform_data->gpio_ctrl(sd, flag);
-
-       return dev->platform_data->gpio0_ctrl(sd, flag);
-}
-
-static int __power_up(struct v4l2_subdev *sd)
-{
-       struct ov5693_device *dev = to_ov5693_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret;
-
-       if (NULL == dev->platform_data) {
-               dev_err(&client->dev,
-                       "no camera_sensor_platform_data");
-               return -ENODEV;
-       }
-
-       /* power control */
-       ret = power_ctrl(sd, 1);
-       if (ret)
-               goto fail_power;
-
-       /* according to DS, at least 5ms is needed between DOVDD and PWDN */
-       /* add this delay time to 10~11ms*/
-       usleep_range(10000, 11000);
-
-       /* gpio ctrl */
-       ret = gpio_ctrl(sd, 1);
-       if (ret) {
-               ret = gpio_ctrl(sd, 1);
-               if (ret)
-                       goto fail_power;
-       }
-
-       /* flis clock control */
-       ret = dev->platform_data->flisclk_ctrl(sd, 1);
-       if (ret)
-               goto fail_clk;
-
-       __cci_delay(up_delay);
-
-       return 0;
-
-fail_clk:
-       gpio_ctrl(sd, 0);
-fail_power:
-       power_ctrl(sd, 0);
-       dev_err(&client->dev, "sensor power-up failed\n");
-
-       return ret;
-}
-
-static int power_down(struct v4l2_subdev *sd)
-{
-       struct ov5693_device *dev = to_ov5693_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret = 0;
-
-       dev->focus = OV5693_INVALID_CONFIG;
-       if (NULL == dev->platform_data) {
-               dev_err(&client->dev,
-                       "no camera_sensor_platform_data");
-               return -ENODEV;
-       }
-
-       ret = dev->platform_data->flisclk_ctrl(sd, 0);
-       if (ret)
-               dev_err(&client->dev, "flisclk failed\n");
-
-       /* gpio ctrl */
-       ret = gpio_ctrl(sd, 0);
-       if (ret) {
-               ret = gpio_ctrl(sd, 0);
-               if (ret)
-                       dev_err(&client->dev, "gpio failed 2\n");
-       }
-
-       /* power control */
-       ret = power_ctrl(sd, 0);
-       if (ret)
-               dev_err(&client->dev, "vprog failed.\n");
-
-       return ret;
-}
-
-static int power_up(struct v4l2_subdev *sd)
-{
-       static const int retry_count = 4;
-       int i, ret;
-
-       for (i = 0; i < retry_count; i++) {
-               ret = __power_up(sd);
-               if (!ret)
-                       return 0;
-
-               power_down(sd);
-       }
-       return ret;
-}
-
-static int ov5693_s_power(struct v4l2_subdev *sd, int on)
-{
-       int ret;
-
-       pr_info("%s: on %d\n", __func__, on);
-       if (on == 0)
-               return power_down(sd);
-       else {
-               ret = power_up(sd);
-               if (!ret) {
-                       ret = ov5693_init(sd);
-                       /* restore settings */
-                       ov5693_res = ov5693_res_preview;
-                       N_RES = N_RES_PREVIEW;
-               }
-       }
-       return ret;
-}
-
-/*
- * distance - calculate the distance
- * @res: resolution
- * @w: width
- * @h: height
- *
- * Get the gap between res_w/res_h and w/h.
- * distance = (res_w/res_h - w/h) / (w/h) * 8192
- * res->width/height smaller than w/h wouldn't be considered.
- * The gap of ratio larger than 1/8 wouldn't be considered.
- * Returns the value of gap or -1 if fail.
- */
-#define LARGEST_ALLOWED_RATIO_MISMATCH 1024
-static int distance(struct ov5693_resolution *res, u32 w, u32 h)
-{
-       int ratio;
-       int distance;
-
-       if (w == 0 || h == 0 ||
-           res->width < w || res->height < h)
-               return -1;
-
-       ratio = res->width << 13;
-       ratio /= w;
-       ratio *= h;
-       ratio /= res->height;
-
-       distance = abs(ratio - 8192);
-
-       if (distance > LARGEST_ALLOWED_RATIO_MISMATCH)
-               return -1;
-
-       return distance;
-}
-
-/* Return the nearest higher resolution index
- * Firstly try to find the approximate aspect ratio resolution
- * If we find multiple same AR resolutions, choose the
- * minimal size.
- */
-static int nearest_resolution_index(int w, int h)
-{
-       int i;
-       int idx = -1;
-       int dist;
-       int min_dist = INT_MAX;
-       int min_res_w = INT_MAX;
-       struct ov5693_resolution *tmp_res = NULL;
-
-       for (i = 0; i < N_RES; i++) {
-               tmp_res = &ov5693_res[i];
-               dist = distance(tmp_res, w, h);
-               if (dist == -1)
-                       continue;
-               if (dist < min_dist) {
-                       min_dist = dist;
-                       idx = i;
-                       min_res_w = ov5693_res[i].width;
-                       continue;
-               }
-               if (dist == min_dist && ov5693_res[i].width < min_res_w)
-                       idx = i;
-       }
-
-       return idx;
-}
-
-static int get_resolution_index(int w, int h)
-{
-       int i;
-
-       for (i = 0; i < N_RES; i++) {
-               if (w != ov5693_res[i].width)
-                       continue;
-               if (h != ov5693_res[i].height)
-                       continue;
-
-               return i;
-       }
-
-       return -1;
-}
-
-/* TODO: remove it. */
-static int startup(struct v4l2_subdev *sd)
-{
-       struct ov5693_device *dev = to_ov5693_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret = 0;
-
-       ret = ov5693_write_reg(client, OV5693_8BIT,
-                                       OV5693_SW_RESET, 0x01);
-       if (ret) {
-               dev_err(&client->dev, "ov5693 reset err.\n");
-               return ret;
-       }
-
-       ret = ov5693_write_reg_array(client, ov5693_global_setting);
-       if (ret) {
-               dev_err(&client->dev, "ov5693 write register err.\n");
-               return ret;
-       }
-
-       ret = ov5693_write_reg_array(client, ov5693_res[dev->fmt_idx].regs);
-       if (ret) {
-               dev_err(&client->dev, "ov5693 write register err.\n");
-               return ret;
-       }
-
-       return ret;
-}
-
-static int ov5693_set_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
-                         struct v4l2_subdev_format *format)
-{
-       struct v4l2_mbus_framefmt *fmt = &format->format;
-       struct ov5693_device *dev = to_ov5693_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       struct camera_mipi_info *ov5693_info = NULL;
-       int ret = 0;
-       int idx;
-       if (format->pad)
-               return -EINVAL;
-       if (!fmt)
-               return -EINVAL;
-       ov5693_info = v4l2_get_subdev_hostdata(sd);
-       if (ov5693_info == NULL)
-               return -EINVAL;
-
-       mutex_lock(&dev->input_lock);
-       idx = nearest_resolution_index(fmt->width, fmt->height);
-       if (idx == -1) {
-               /* return the largest resolution */
-               fmt->width = ov5693_res[N_RES - 1].width;
-               fmt->height = ov5693_res[N_RES - 1].height;
-       } else {
-               fmt->width = ov5693_res[idx].width;
-               fmt->height = ov5693_res[idx].height;
-       }
-
-       fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
-       if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
-               cfg->try_fmt = *fmt;
-               mutex_unlock(&dev->input_lock);
-               return 0;
-       }
-
-       dev->fmt_idx = get_resolution_index(fmt->width, fmt->height);
-       if (dev->fmt_idx == -1) {
-               dev_err(&client->dev, "get resolution fail\n");
-               mutex_unlock(&dev->input_lock);
-               return -EINVAL;
-       }
-
-       ret = startup(sd);
-       if (ret) {
-               int i = 0;
-               dev_err(&client->dev, "ov5693 startup err, retry to power up\n");
-               for (i = 0; i < OV5693_POWER_UP_RETRY_NUM; i++) {
-                       dev_err(&client->dev,
-                               "ov5693 retry to power up %d/%d times, result: ",
-                               i+1, OV5693_POWER_UP_RETRY_NUM);
-                       power_down(sd);
-                       ret = power_up(sd);
-                       if (!ret) {
-                               mutex_unlock(&dev->input_lock);
-                               ov5693_init(sd);
-                               mutex_lock(&dev->input_lock);
-                       } else {
-                               dev_err(&client->dev, "power up failed, continue\n");
-                               continue;
-                       }
-                       ret = startup(sd);
-                       if (ret) {
-                               dev_err(&client->dev, " startup FAILED!\n");
-                       } else {
-                               dev_err(&client->dev, " startup SUCCESS!\n");
-                               break;
-                       }
-               }
-       }
-
-       /*
-        * After sensor settings are set to HW, sometimes stream is started.
-        * This would cause ISP timeout because ISP is not ready to receive
-        * data yet. So add stop streaming here.
-        */
-       ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_SW_STREAM,
-                               OV5693_STOP_STREAMING);
-       if (ret)
-               dev_warn(&client->dev, "ov5693 stream off err\n");
-
-       ret = ov5693_get_intg_factor(client, ov5693_info,
-                                       &ov5693_res[dev->fmt_idx]);
-       if (ret) {
-               dev_err(&client->dev, "failed to get integration_factor\n");
-               goto err;
-       }
-
-       ov5693_info->metadata_width = fmt->width * 10 / 8;
-       ov5693_info->metadata_height = 1;
-       ov5693_info->metadata_effective_width = &ov5693_embedded_effective_size;
-
-err:
-       mutex_unlock(&dev->input_lock);
-       return ret;
-}
-static int ov5693_get_fmt(struct v4l2_subdev *sd,
-                         struct v4l2_subdev_pad_config *cfg,
-                         struct v4l2_subdev_format *format)
-{
-       struct v4l2_mbus_framefmt *fmt = &format->format;
-       struct ov5693_device *dev = to_ov5693_sensor(sd);
-       if (format->pad)
-               return -EINVAL;
-
-       if (!fmt)
-               return -EINVAL;
-
-       fmt->width = ov5693_res[dev->fmt_idx].width;
-       fmt->height = ov5693_res[dev->fmt_idx].height;
-       fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10;
-
-       return 0;
-}
-
-static int ov5693_detect(struct i2c_client *client)
-{
-       struct i2c_adapter *adapter = client->adapter;
-       u16 high, low;
-       int ret;
-       u16 id;
-       u8 revision;
-
-       if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
-               return -ENODEV;
-
-       ret = ov5693_read_reg(client, OV5693_8BIT,
-                                       OV5693_SC_CMMN_CHIP_ID_H, &high);
-       if (ret) {
-               dev_err(&client->dev, "sensor_id_high = 0x%x\n", high);
-               return -ENODEV;
-       }
-       ret = ov5693_read_reg(client, OV5693_8BIT,
-                                       OV5693_SC_CMMN_CHIP_ID_L, &low);
-       id = ((((u16) high) << 8) | (u16) low);
-
-       if (id != OV5693_ID) {
-               dev_err(&client->dev, "sensor ID error 0x%x\n", id);
-               return -ENODEV;
-       }
-
-       ret = ov5693_read_reg(client, OV5693_8BIT,
-                                       OV5693_SC_CMMN_SUB_ID, &high);
-       revision = (u8) high & 0x0f;
-
-       dev_dbg(&client->dev, "sensor_revision = 0x%x\n", revision);
-       dev_dbg(&client->dev, "detect ov5693 success\n");
-       return 0;
-}
-
-static int ov5693_s_stream(struct v4l2_subdev *sd, int enable)
-{
-       struct ov5693_device *dev = to_ov5693_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret;
-
-       mutex_lock(&dev->input_lock);
-
-       ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_SW_STREAM,
-                               enable ? OV5693_START_STREAMING :
-                               OV5693_STOP_STREAMING);
-
-       mutex_unlock(&dev->input_lock);
-
-       return ret;
-}
-
-
-static int ov5693_s_config(struct v4l2_subdev *sd,
-                          int irq, void *platform_data)
-{
-       struct ov5693_device *dev = to_ov5693_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-       int ret = 0;
-
-       if (platform_data == NULL)
-               return -ENODEV;
-
-       dev->platform_data =
-               (struct camera_sensor_platform_data *)platform_data;
-
-       mutex_lock(&dev->input_lock);
-       /* power off the module, then power on it in future
-        * as first power on by board may not fulfill the
-        * power on sequqence needed by the module
-        */
-       ret = power_down(sd);
-       if (ret) {
-               dev_err(&client->dev, "ov5693 power-off err.\n");
-               goto fail_power_off;
-       }
-
-       ret = power_up(sd);
-       if (ret) {
-               dev_err(&client->dev, "ov5693 power-up err.\n");
-               goto fail_power_on;
-       }
-
-       if (!dev->vcm)
-               dev->vcm = vcm_detect(client);
-
-       ret = dev->platform_data->csi_cfg(sd, 1);
-       if (ret)
-               goto fail_csi_cfg;
-
-       /* config & detect sensor */
-       ret = ov5693_detect(client);
-       if (ret) {
-               dev_err(&client->dev, "ov5693_detect err s_config.\n");
-               goto fail_csi_cfg;
-       }
-
-       dev->otp_data = ov5693_otp_read(sd);
-
-       /* turn off sensor, after probed */
-       ret = power_down(sd);
-       if (ret) {
-               dev_err(&client->dev, "ov5693 power-off err.\n");
-               goto fail_csi_cfg;
-       }
-       mutex_unlock(&dev->input_lock);
-
-       return ret;
-
-fail_csi_cfg:
-       dev->platform_data->csi_cfg(sd, 0);
-fail_power_on:
-       power_down(sd);
-       dev_err(&client->dev, "sensor power-gating failed\n");
-fail_power_off:
-       mutex_unlock(&dev->input_lock);
-       return ret;
-}
-
-static int ov5693_g_parm(struct v4l2_subdev *sd,
-                       struct v4l2_streamparm *param)
-{
-       struct ov5693_device *dev = to_ov5693_sensor(sd);
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
-
-       if (!param)
-               return -EINVAL;
-
-       if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-               dev_err(&client->dev,  "unsupported buffer type.\n");
-               return -EINVAL;
-       }
-
-       memset(param, 0, sizeof(*param));
-       param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-       if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) {
-               param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
-               param->parm.capture.timeperframe.numerator = 1;
-               param->parm.capture.capturemode = dev->run_mode;
-               param->parm.capture.timeperframe.denominator =
-                       ov5693_res[dev->fmt_idx].fps;
-       }
-       return 0;
-}
-
-static int ov5693_s_parm(struct v4l2_subdev *sd,
-                       struct v4l2_streamparm *param)
-{
-       struct ov5693_device *dev = to_ov5693_sensor(sd);
-       dev->run_mode = param->parm.capture.capturemode;
-
-       mutex_lock(&dev->input_lock);
-       switch (dev->run_mode) {
-       case CI_MODE_VIDEO:
-               ov5693_res = ov5693_res_video;
-               N_RES = N_RES_VIDEO;
-               break;
-       case CI_MODE_STILL_CAPTURE:
-               ov5693_res = ov5693_res_still;
-               N_RES = N_RES_STILL;
-               break;
-       default:
-               ov5693_res = ov5693_res_preview;
-               N_RES = N_RES_PREVIEW;
-       }
-       mutex_unlock(&dev->input_lock);
-       return 0;
-}
-
-static int ov5693_g_frame_interval(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_frame_interval *interval)
-{
-       struct ov5693_device *dev = to_ov5693_sensor(sd);
-
-       interval->interval.numerator = 1;
-       interval->interval.denominator = ov5693_res[dev->fmt_idx].fps;
-
-       return 0;
-}
-
-static int ov5693_enum_mbus_code(struct v4l2_subdev *sd,
-                                struct v4l2_subdev_pad_config *cfg,
-                                struct v4l2_subdev_mbus_code_enum *code)
-{
-       if (code->index >= MAX_FMTS)
-               return -EINVAL;
-
-       code->code = MEDIA_BUS_FMT_SBGGR10_1X10;
-       return 0;
-}
-
-static int ov5693_enum_frame_size(struct v4l2_subdev *sd,
-                                 struct v4l2_subdev_pad_config *cfg,
-                                 struct v4l2_subdev_frame_size_enum *fse)
-{
-       int index = fse->index;
-
-       if (index >= N_RES)
-               return -EINVAL;
-
-       fse->min_width = ov5693_res[index].width;
-       fse->min_height = ov5693_res[index].height;
-       fse->max_width = ov5693_res[index].width;
-       fse->max_height = ov5693_res[index].height;
-
-       return 0;
-
-}
-
-static const struct v4l2_subdev_video_ops ov5693_video_ops = {
-       .s_stream = ov5693_s_stream,
-       .g_parm = ov5693_g_parm,
-       .s_parm = ov5693_s_parm,
-       .g_frame_interval = ov5693_g_frame_interval,
-};
-
-static const struct v4l2_subdev_core_ops ov5693_core_ops = {
-       .s_power = ov5693_s_power,
-       .ioctl = ov5693_ioctl,
-};
-
-static const struct v4l2_subdev_pad_ops ov5693_pad_ops = {
-       .enum_mbus_code = ov5693_enum_mbus_code,
-       .enum_frame_size = ov5693_enum_frame_size,
-       .get_fmt = ov5693_get_fmt,
-       .set_fmt = ov5693_set_fmt,
-};
-
-static const struct v4l2_subdev_ops ov5693_ops = {
-       .core = &ov5693_core_ops,
-       .video = &ov5693_video_ops,
-       .pad = &ov5693_pad_ops,
-};
-
-static int ov5693_remove(struct i2c_client *client)
-{
-       struct v4l2_subdev *sd = i2c_get_clientdata(client);
-       struct ov5693_device *dev = to_ov5693_sensor(sd);
-       dev_dbg(&client->dev, "ov5693_remove...\n");
-
-       dev->platform_data->csi_cfg(sd, 0);
-
-       v4l2_device_unregister_subdev(sd);
-
-       atomisp_gmin_remove_subdev(sd);
-
-       media_entity_cleanup(&dev->sd.entity);
-       v4l2_ctrl_handler_free(&dev->ctrl_handler);
-       kfree(dev);
-
-       return 0;
-}
-
-static int ov5693_probe(struct i2c_client *client,
-                       const struct i2c_device_id *id)
-{
-       struct ov5693_device *dev;
-       int i2c;
-       int ret = 0;
-       void *pdata = client->dev.platform_data;
-       struct acpi_device *adev;
-       unsigned int i;
-
-       /* Firmware workaround: Some modules use a "secondary default"
-        * address of 0x10 which doesn't appear on schematics, and
-        * some BIOS versions haven't gotten the memo.  Work around
-        * via config. */
-       i2c = gmin_get_var_int(&client->dev, "I2CAddr", -1);
-       if (i2c != -1) {
-               dev_info(&client->dev,
-               "Overriding firmware-provided I2C address (0x%x) with 0x%x\n",
-                        client->addr, i2c);
-               client->addr = i2c;
-       }
-
-       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-       if (!dev) {
-               dev_err(&client->dev, "out of memory\n");
-               return -ENOMEM;
-       }
-
-       mutex_init(&dev->input_lock);
-
-       dev->fmt_idx = 0;
-       v4l2_i2c_subdev_init(&(dev->sd), client, &ov5693_ops);
-
-       adev = ACPI_COMPANION(&client->dev);
-       if (adev) {
-               adev->power.flags.power_resources = 0;
-               pdata = gmin_camera_platform_data(&dev->sd,
-                                                 ATOMISP_INPUT_FORMAT_RAW_10,
-                                                 atomisp_bayer_order_bggr);
-       }
-
-       if (!pdata)
-               goto out_free;
-
-       ret = ov5693_s_config(&dev->sd, client->irq, pdata);
-       if (ret)
-               goto out_free;
-
-       ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA);
-       if (ret)
-               goto out_free;
-
-       dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-       dev->pad.flags = MEDIA_PAD_FL_SOURCE;
-       dev->format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
-       dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
-       ret =
-           v4l2_ctrl_handler_init(&dev->ctrl_handler,
-                                  ARRAY_SIZE(ov5693_controls));
-       if (ret) {
-               ov5693_remove(client);
-               return ret;
-       }
-
-       for (i = 0; i < ARRAY_SIZE(ov5693_controls); i++)
-               v4l2_ctrl_new_custom(&dev->ctrl_handler, &ov5693_controls[i],
-                                    NULL);
-
-       if (dev->ctrl_handler.error) {
-               ov5693_remove(client);
-               return dev->ctrl_handler.error;
-       }
-
-       /* Use same lock for controls as for everything else. */
-       dev->ctrl_handler.lock = &dev->input_lock;
-       dev->sd.ctrl_handler = &dev->ctrl_handler;
-
-       ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad);
-       if (ret)
-               ov5693_remove(client);
-
-       return ret;
-out_free:
-       v4l2_device_unregister_subdev(&dev->sd);
-       kfree(dev);
-       return ret;
-}
-
-MODULE_DEVICE_TABLE(i2c, ov5693_id);
-
-static const struct acpi_device_id ov5693_acpi_match[] = {
-       {"INT33BE"},
-       {},
-};
-MODULE_DEVICE_TABLE(acpi, ov5693_acpi_match);
-
-static struct i2c_driver ov5693_driver = {
-       .driver = {
-               .name = OV5693_NAME,
-               .acpi_match_table = ACPI_PTR(ov5693_acpi_match),
-       },
-       .probe = ov5693_probe,
-       .remove = ov5693_remove,
-       .id_table = ov5693_id,
-};
-
-static int init_ov5693(void)
-{
-       return i2c_add_driver(&ov5693_driver);
-}
-
-static void exit_ov5693(void)
-{
-
-       i2c_del_driver(&ov5693_driver);
-}
-
-module_init(init_ov5693);
-module_exit(exit_ov5693);
-
-MODULE_DESCRIPTION("A low-level driver for OmniVision 5693 sensors");
-MODULE_LICENSE("GPL");