[Meego-kernel] [MFLD Camera - PATCH v3 2/9] iCDK primary camera (dis71430m) sensor driver based on v4l2 subdev framework

Zhang, Xiaolin xiaolin.zhang at intel.com
Wed Dec 1 10:52:02 PST 2010


>From 79e6dc59fd7a819231da4b241e6c85795419a60d Mon Sep 17 00:00:00 2001
From: Xiaolin Zhang <xiaolin.zhang at intel.com>
Date: Wed, 1 Dec 2010 21:25:14 +0800
Subject: [MFLD Camera - PATCH v3 2/9] iCDK primary camera (dis71430m) sensor driver based on v4l2 subdev
 framework.

Signed-off-by: Xiaolin Zhang <xiaolin.zhang at intel.com>
---
 drivers/media/video/mfld_ci/discam/cam_gpio.h    |   32 +
 drivers/media/video/mfld_ci/discam/dis71430m.h   |   84 +
 drivers/media/video/mfld_ci/discam/discam.c      | 3376 ++++++++++++++++++++++
 drivers/media/video/mfld_ci/discam/discam.h      |  342 +++
 drivers/media/video/mfld_ci/discam/discam_cmd.h  |  403 +++
 drivers/media/video/mfld_ci/discam/sensor_com.h  |  152 +
 drivers/media/video/mfld_ci/discam/to_upstream.h |   37 +
 7 files changed, 4426 insertions(+), 0 deletions(-)
 create mode 100644 drivers/media/video/mfld_ci/discam/cam_gpio.h
 create mode 100644 drivers/media/video/mfld_ci/discam/dis71430m.h
 create mode 100644 drivers/media/video/mfld_ci/discam/discam.c
 create mode 100644 drivers/media/video/mfld_ci/discam/discam.h
 create mode 100644 drivers/media/video/mfld_ci/discam/discam_cmd.h
 create mode 100644 drivers/media/video/mfld_ci/discam/sensor_com.h
 create mode 100644 drivers/media/video/mfld_ci/discam/to_upstream.h

diff --git a/drivers/media/video/mfld_ci/discam/cam_gpio.h b/drivers/media/video/mfld_ci/discam/cam_gpio.h
new file mode 100644
index 0000000..3c14995
--- /dev/null
+++ b/drivers/media/video/mfld_ci/discam/cam_gpio.h
@@ -0,0 +1,32 @@
+/*
+ * Support for Medfield Penwell Camera Imaging ISP subsystem.
+ *
+ * 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.
+ *
+ */
+
+#ifndef        __CAM_GPIO_H__
+#define        __CAM_GPIO_H__
+
+#define        __GP_AON(offset)        (offset)
+#define        __GP_CORE(offset)       (96 + (offset))
+
+#define        GP_CAMERA_1_POWER_DOWN  __GP_CORE(80)
+#define        GP_CAMERA_0_RESET       __GP_CORE(81)
+#define        GP_CAMERA_1_RESET       __GP_CORE(82)
+
+#endif
diff --git a/drivers/media/video/mfld_ci/discam/dis71430m.h b/drivers/media/video/mfld_ci/discam/dis71430m.h
new file mode 100644
index 0000000..e22cb30
--- /dev/null
+++ b/drivers/media/video/mfld_ci/discam/dis71430m.h
@@ -0,0 +1,84 @@
+/*
+ * Support for Medfield Penwell Camera Imaging ISP subsystem.
+ *
+ * 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.
+ *
+ */
+
+#ifndef        __DIS71430M_H__
+#define        __DIS71430M_H__
+
+#include "discam.h"
+#define        DIS71430M_FW_FILE  "dis_cam14mp.bin"
+#define        DIS71430M_NAME  "dis71430m"
+
+#define        DIS71430M_ADDR  0x69
+#define        DIS71430M_SRAM_ADDR             0x67
+#define        DIS71430M_FW_VERSION            0x48    /* eclipse */
+#define        DIS71430M_SENSOR_ID             0xe810  /* rev 1b */
+#define        DIS71430M_SENSOR_REVISION       0xb1    /* rev 1b */
+#define        DIS71430M_SENSOR_REVISION_PO    0xb1
+
+enum ENUM_VF_MODE_FRAMERATE {
+       ENUM_VF_MODE_FPS_15 = 15,
+       ENUM_VF_MODE_FPS_30 = 30,
+       ENUM_VF_MODE_FPS_90 = 90
+};
+
+/* supported resolution, bit, and max fps */
+static struct __dis_output_format g_dis71430m_fmts[] = {
+       __dis_vf_output_format_entry(4416, 3312,
+                                    V4L2_PIX_FMT_SBGGR10, ENUM_VF_MODE_FPS_15,
+                                    DIS_VIEWFINDER_MODE_4416_3312),
+       __dis_vf_output_format_entry(2112, 1188,
+                                    V4L2_PIX_FMT_SBGGR10, ENUM_VF_MODE_FPS_15,
+                                    DIS_VIEWFINDER_MODE_2112_1188),
+       __dis_vf_output_format_entry(1408, 792,
+                                    V4L2_PIX_FMT_SBGGR10, ENUM_VF_MODE_FPS_15,
+                                    DIS_VIEWFINDER_MODE_1408_792),
+       __dis_vf_output_format_entry(1104, 828,
+                                    V4L2_PIX_FMT_SBGGR10, ENUM_VF_MODE_FPS_15,
+                                    DIS_VIEWFINDER_MODE_1104_828),
+       __dis_ss_output_format_entry(4416, 3312,
+                                    V4L2_PIX_FMT_SBGGR10, ENUM_VF_MODE_FPS_15,
+                                    DIS_SNAPSHOT_MODE_4416_3312),
+       __dis_ss_output_format_entry(1920, 1080,
+                                    V4L2_PIX_FMT_SBGGR10, ENUM_VF_MODE_FPS_30,
+                                    DIS_SNAPSHOT_MODE_1080P),
+};
+
+static struct discam_driver g_dis71430m_driver = {
+       .name = DIS71430M_NAME,
+       .addr = DIS71430M_ADDR,
+       .fmts = g_dis71430m_fmts,
+       .fmt_nr = 9,
+       .default_vf_mode = DIS_VIEWFINDER_MODE_VGA_30FPS,
+       .default_ss_mode = DIS_SNAPSHOT_MODE_4416_3312,
+       .fw_file = DIS71430M_FW_FILE,
+       .fw = NULL, /* filled by request_firmware */
+};
+
+static struct discam_driver *g_this_camera = &g_dis71430m_driver;
+
+/*
+ * driver module name for DIS camera, used for ISP driver to probe.
+ */
+#define        DISCAM_NAME     DIS71430M_NAME
+
+MODULE_DESCRIPTION("A low-level driver for DIS71430M camera. Version 0.1");
+
+#endif
diff --git a/drivers/media/video/mfld_ci/discam/discam.c b/drivers/media/video/mfld_ci/discam/discam.c
new file mode 100644
index 0000000..0f4afbc
--- /dev/null
+++ b/drivers/media/video/mfld_ci/discam/discam.c
@@ -0,0 +1,3376 @@
+/*
+ * Support for Medfield Penwell Camera Imaging ISP subsystem.
+ *
+ * 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/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/fs.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/videodev2.h>
+#include <linux/io.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv.h>
+#include <linux/firmware.h>
+#include "mfldisp_sensor.h"
+#include "mfldisp_v4l2.h"
+#include "dis71430m.h"
+
+#include "discam_cmd.h"
+#include "to_upstream.h"
+
+#define        __check_ret(ret, fmt, arg ...)  \
+       do { \
+               if ((ret)) { \
+                       __discam_err(fmt, ##arg); \
+               } \
+       } while (0)
+
+#define        __check_ret_goto(ret, label, fmt, arg ...)      \
+       do { \
+               if ((ret)) { \
+                       __discam_err(fmt, ##arg); \
+                       goto label; \
+               } \
+       } while (0)
+
+#define        __check_ret_return(ret, exp, fmt, arg ...)      \
+       do { \
+               if ((ret)) { \
+                       __discam_err(fmt, ##arg); \
+                       return exp; \
+               } \
+       } while (0)
+
+#define        __check_dev_null(dev)\
+       do { \
+               if (!dev) \
+                       __discam_err("NULL device.\n");\
+       } while (0)
+
+#define        __check_dev_null_return(dev, exp)\
+       do { \
+               if (!dev) {\
+                       __discam_err("NULL device.\n");\
+                       return exp;\
+               } \
+       } while (0)
+
+/*
+ * module arguments
+ */
+int g_discam_dbg = DBG_LEVEL_1;
+module_param(g_discam_dbg, int, 0644);
+static int g_discam_test;
+module_param(g_discam_test, int, 0644);
+static int g_discam_start_vf;
+module_param(g_discam_start_vf, int, 0644);
+static int g_discam_vf_mode = 0x0;     /* vga at 30fps default */
+module_param(g_discam_vf_mode, int, 0644);
+
+static const struct __dis_output_format *__get_vf_format(__u8 modeval)
+{
+       int i;
+
+       for (i = 0; i < g_this_camera->fmt_nr; i++) {
+               if (g_this_camera->fmts[i].mode != DIS_VIEWFINDER_MODE)
+                       continue;
+               if (g_this_camera->fmts[i].modeval == modeval)
+                       return &(g_this_camera->fmts[i]);
+       }
+
+       return NULL;
+}
+
+static const struct __dis_output_format *__get_ss_format(__u8 modeval)
+{
+       int i;
+
+       for (i = 0; i < g_this_camera->fmt_nr; i++) {
+               if (g_this_camera->fmts[i].mode != DIS_SNAPSHOT_MODE)
+                       continue;
+               if (g_this_camera->fmts[i].modeval == modeval)
+                       return &(g_this_camera->fmts[i]);
+       }
+
+       return NULL;
+}
+
+/*
+ * get current time, in micro seconds
+ */
+static unsigned long __get_cur_time(void)
+{
+       return jiffies_to_msecs(jiffies);
+}
+
+/*
+ * i2c read/write function
+ */
+static int __discam_read(struct i2c_client *client, __u8 reg, __u8 * val)
+{
+       int ret;
+       int i;
+       struct i2c_msg msg[2];
+       u8 msgbuf[2];
+       u8 ret_val = 0;
+
+       /* Read needs two message to go */
+       memset(&msg, 0, sizeof(msg));
+       msgbuf[0] = 0;
+       msgbuf[1] = 0;
+       i = 0;
+       msgbuf[i++] = (__u8) reg;
+       msg[0].addr = client->addr;
+       msg[0].buf = msgbuf;
+       msg[0].len = i;
+
+       msg[1].addr = client->addr;
+       msg[1].flags = I2C_M_RD;
+       msg[1].buf = &ret_val;
+       msg[1].len = 1;
+
+       __discam_dbg(DBG_LEVEL_2, "slave addr = 0x%x\n", client->addr);
+
+       __discam_dbg(DBG_LEVEL_2, "msgbuf[0] = 0x%x (reg).\n", msgbuf[0]);
+
+       ret = i2c_transfer(client->adapter, &msg[0], 2);
+       ret = (ret == 2) ? 0 : -1;
+       __check_ret_return(ret, -1, "i2c read err: reg = 0x%x\n", reg);
+
+       (*val) = ret_val;
+
+       return ret;
+}
+
+static int __discam_write(struct i2c_client *client, __u8 reg, __u8 val)
+{
+       int ret, i;
+       struct i2c_msg msg;
+       u8 msgbuf[3];
+
+       /* Writing only needs one message */
+       memset(&msg, 0, sizeof(msg));
+       i = 0;
+       msgbuf[i++] = (__u8) reg;
+       msgbuf[i++] = val;
+
+       msg.addr = client->addr;
+       msg.flags = 0;
+       msg.buf = msgbuf;
+       msg.len = i;
+
+       __discam_dbg(DBG_LEVEL_2, "slave addr = 0x%x\n", client->addr);
+
+       __discam_dbg(DBG_LEVEL_2,       \
+               "msgbuf[0] = 0x%x (reg), msgbuf[1] = 0x%x (val).\n",    \
+               msgbuf[0], msgbuf[1]);
+
+       ret = i2c_transfer(client->adapter, &msg, 1);
+       ret = (ret == 1) ? 0 : -1;
+       __check_ret_return(ret, -1, "i2c write err: reg = 0x%x\n", reg);
+
+       return ret;
+}
+
+/* i2c write (16 bit register) */
+static int __sram_write(struct i2c_client *client, __u16 reg, __u8 val)
+{
+       int ret, i;
+       struct i2c_msg msg;
+       u8 msgbuf[3];
+       unsigned short addr;
+
+       /* Writing only needs one message */
+       memset(&msg, 0, sizeof(msg));
+       i = 0;
+       msgbuf[i++] = (__u8) reg;
+       msgbuf[i++] = (__u8) (reg >> 8);
+       msgbuf[i++] = val;
+
+       addr = client->addr;
+       client->addr = 0x67;
+
+       msg.addr = client->addr;
+       msg.flags = 0;
+       msg.buf = msgbuf;
+       msg.len = i;
+
+       __discam_dbg(DBG_LEVEL_2,       \
+               "msgbuf[0] = 0x%x (LSB), msgbuf[1] = 0x%x (MSB).\n",    \
+               msgbuf[0], msgbuf[1]);
+
+       ret = i2c_transfer(client->adapter, &msg, 1);
+       ret = (ret == 1) ? 0 : -1;
+       __check_ret_return(ret, -1, "i2c write err: reg = 0x%x\n", reg);
+
+       client->addr = addr;
+
+       return ret;
+}
+
+#define        DIS_CMD_WAIT_TIME       5000    /* in micro seconds */
+static int __wait_cmd(struct i2c_client *client)
+{
+       int ret;
+       unsigned long st, et;
+       __u8 status;
+
+       st = __get_cur_time();
+       do {
+               ret = __discam_read(client, DIS_PROC_CMD, &status);
+               /* if err, return -1 immediately */
+               __check_ret_return(ret, -1, "__discam_read err.\n");
+               msleep(20);
+               et = __get_cur_time();
+       } while ((status != DIS_CMD_STATUS_IDLE)
+                && ((et - st) < DIS_CMD_WAIT_TIME));
+
+       if ((et - st) >= DIS_CMD_WAIT_TIME) {
+               __discam_err("__wait_cmd time out.\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+/*
+ * excute a command.
+ *
+ * user specify command value to cmd, and the return value is stored in ret.
+ * this function will wait until the command is finished
+ * (polling DIS_PROC_CMD until its value become DIS_CMD_ID_IDLE)
+ */
+int __discam_excute_cmd(struct i2c_client *client, struct dis_cmd *cmd)
+{
+       int ret = 0;
+
+       ret += __discam_write(client, DIS_PROC_REG0, cmd->proc_reg0);
+       __check_ret(ret, "__discam_write err.\n");
+
+       ret += __discam_write(client, DIS_PROC_REG1, cmd->proc_reg1);
+       __check_ret(ret, "__discam_write err.\n");
+
+       ret += __discam_write(client, DIS_PROC_REG2, cmd->proc_reg2);
+       __check_ret(ret, "__discam_write err.\n");
+
+       ret += __discam_write(client, DIS_PROC_REG3, cmd->proc_reg3);
+       __check_ret(ret, "__discam_write err.\n");
+
+       /* write value to DIS_PROC_CMD will trigger the command */
+       ret += __discam_write(client, DIS_PROC_CMD, cmd->proc_cmd);
+       __check_ret_return(ret, -1, "__discam_write err.\n");
+
+       /*
+        * return immediately if __wait_cmd failed.
+        */
+       ret += __wait_cmd(client);
+       __check_ret(ret, "__wait_cmd err.\n");
+
+       /* read return value to related variable */
+       ret += __discam_read(client, DIS_PROC_REG0, &(cmd->ret_reg0));
+       __check_ret(ret, "__discam_read err.\n");
+
+       ret += __discam_read(client, DIS_PROC_REG1, &(cmd->ret_reg1));
+       __check_ret(ret, "__discam_read err.\n");
+
+       ret += __discam_read(client, DIS_PROC_REG2, &(cmd->ret_reg2));
+       __check_ret(ret, "__discam_read err.\n");
+
+       ret += __discam_read(client, DIS_PROC_REG3, &(cmd->ret_reg3));
+       __check_ret(ret, "__discam_read err.\n");
+
+       return ret;
+}
+
+/*
+ * startup and initialization.
+ */
+static int __startup(struct i2c_client *client)
+{
+       int ret = 0;
+       struct dis_cmd cmd;
+       int i;
+       const char *fw_data;
+       int fw_size;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       __discam_dbg(DBG_LEVEL_1, "request GPIO camera_0 RESET pin.\n");
+
+       ret = gpio_request(GP_CAMERA_0_RESET, "Camera 0 reset");
+       __check_ret_return(ret, -1, "gpio_request err.\n");
+
+       __discam_dbg(DBG_LEVEL_1, "done.\n");
+
+       /* 1) release external reset pin
+        *  a) set reset GPIO pin low
+        *  b) set reset GPIO pin high
+        */
+       __discam_dbg(DBG_LEVEL_1, "reset external pin...\n");
+
+       ret = gpio_direction_output(GP_CAMERA_0_RESET, 0);
+       __check_ret_return(ret, -1, "gpio_direction_output err.\n");
+       ret = gpio_direction_output(GP_CAMERA_0_RESET, 1);
+       __check_ret_return(ret, -1, "gpio_direction_output err.\n");
+
+       gpio_free(GP_CAMERA_0_RESET);
+
+       __discam_dbg(DBG_LEVEL_1, "reset external done...\n");
+
+       /* 2) set internal SRAM device ID to 0x67, upload fw and boot fw */
+       __discam_dbg(DBG_LEVEL_1, "set internal SRAM device ID...\n");
+       ret = __discam_write(client, 0x19, 0x67);
+       __check_ret_return(ret, -1, "set internal SRAM device ID err.\n");
+       __discam_dbg(DBG_LEVEL_1, "set internal SRAM device ID... done.\n");
+
+       __discam_dbg(DBG_LEVEL_1,
+               "reset processor and set start address 0...\n");
+       ret = __discam_write(client, 0x18, 0x02);
+       __check_ret_return(ret, -1,
+                          "reset processor and set start address 0...\n");
+       __discam_dbg(DBG_LEVEL_1,
+               "reset processor and set start address 0... done.\n");
+
+       __discam_dbg(DBG_LEVEL_1, "upload FW binary to SRAM...\n");
+
+       fw_data = g_this_camera->fw->data;
+       fw_size = g_this_camera->fw->size;
+       for (i = 0; i < fw_size; i++) {
+               ret = __sram_write(client, (__u16) i, fw_data[i]);
+               __check_ret_return(ret, -1, "__discam_sram_write err.\n");
+       }
+       __discam_dbg(DBG_LEVEL_1, "upload FW binary to SRAM... done.\n");
+
+       __discam_dbg(DBG_LEVEL_1, "boot from SRAM...\n");
+       ret = __discam_write(client, 0x18, 0x03);
+       __check_ret_return(ret, -1, "__discam_write err.\n");
+
+       __wait_cmd(client);
+
+       __discam_dbg(DBG_LEVEL_1, "boot from SRAM... done.\n");
+
+       /* 3) DIS_CMD_REQ_INIT */
+
+       __discam_dbg(DBG_LEVEL_1, "DIS_CMD_REQ_INIT...\n");
+       dis_cmd_clear(&cmd);
+       cmd.proc_cmd = DIS_CMD_REQ_INIT;
+
+       ret = __discam_excute_cmd(client, &cmd);
+       __check_ret_return(ret, -1, "__discam_excute_cmd err.\n");
+       __discam_check_cmd_retval_return(cmd);
+
+       __discam_dbg(DBG_LEVEL_1, "DIS_CMD_REQ_INIT... done...\n");
+
+       /* 4) CMD_REQ_MOTOR_INIT */
+       __discam_dbg(DBG_LEVEL_1, "DIS_CMD_REQ_MOTOR_INIT...\n");
+       dis_cmd_clear(&cmd);
+       cmd.proc_cmd = DIS_CMD_REQ_MOTOR_INIT;
+
+       ret = __discam_excute_cmd(client, &cmd);
+       __check_ret_return(ret, -1, "__discam_excute_cmd err.\n");
+       __discam_check_cmd_retval_return(cmd);
+
+       __discam_dbg(DBG_LEVEL_1, "DIS_CMD_REQ_MOTOR_INIT... done...\n");
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+static int __get_fw_version(struct i2c_client *client,
+                           __u8 *version, __u16 *revision)
+{
+       int ret = 0;
+       struct dis_cmd cmd;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       dis_cmd_clear(&cmd);
+
+       cmd.proc_cmd = DIS_CMD_GET_VERSION;
+       cmd.proc_reg0 = 0x00;
+
+       ret = __discam_excute_cmd(client, &cmd);
+       __check_ret_return(ret, -1, "__discam_excute_cmd err.\n");
+       __discam_check_cmd_retval_return(cmd);
+
+       (*version) = cmd.ret_reg1;
+       (*revision) = ((((__u16) cmd.ret_reg2) << 8) | ((__u16) cmd.ret_reg3));
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return ret;
+}
+
+static int __get_sensor_version(struct i2c_client *client,
+                               __u16 *id, __u8 *revision)
+{
+       int ret = 0;
+       struct dis_cmd cmd;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       dis_cmd_clear(&cmd);
+
+       cmd.proc_cmd = DIS_CMD_GET_VERSION;
+       cmd.proc_reg0 = 0x01;
+
+       ret = __discam_excute_cmd(client, &cmd);
+       __check_ret_return(ret, -1, "__discam_excute_cmd err.\n");
+       __discam_check_cmd_retval_return(cmd);
+
+       (*revision) = cmd.ret_reg1;
+       (*id) = ((((__u16) cmd.ret_reg2) << 8) | ((__u16) cmd.ret_reg3));
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return ret;
+}
+
+static int __power_down(struct i2c_client *client)
+{
+       int ret = 0;
+       struct dis_cmd cmd;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       dis_cmd_clear(&cmd);
+
+       cmd.proc_cmd = DIS_CMD_REQ_POWER_CTRL;
+       cmd.proc_reg0 = 0x01;   /* power down */
+       cmd.proc_reg1 = 0x01;
+
+       ret = __discam_excute_cmd(client, &cmd);
+       __check_ret_return(ret, -1, "__discam_excute_cmd err.\n");
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return ret;
+}
+
+static int __standby(struct i2c_client *client)
+{
+       int ret = 0;
+       struct dis_cmd cmd;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       dis_cmd_clear(&cmd);
+
+       cmd.proc_cmd = DIS_CMD_REQ_POWER_CTRL;
+       cmd.proc_reg0 = 0x03;   /* standby */
+       cmd.proc_reg1 = 0x00;
+
+       ret = __discam_excute_cmd(client, &cmd);
+       __check_ret_return(ret, -1, "__discam_excute_cmd err.\n");
+       __discam_check_cmd_retval_return(cmd);
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return ret;
+}
+
+/*
+ * wake up from standby mode.
+ */
+static int __wakeup(struct i2c_client *client)
+{
+       int ret = 0;
+       struct dis_cmd cmd;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       dis_cmd_clear(&cmd);
+
+       cmd.proc_cmd = DIS_CMD_REQ_POWER_CTRL;
+       cmd.proc_reg0 = 0x03;   /* standby */
+       cmd.proc_reg1 = 0x01;   /* restart */
+
+       ret = __discam_excute_cmd(client, &cmd);
+       __check_ret_return(ret, -1, "__discam_excute_cmd err.\n");
+       __discam_check_cmd_retval_return(cmd);
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return ret;
+}
+
+static int __start_viewfinder(struct i2c_client *client, __u8 mode)
+{
+       int ret = 0;
+       struct dis_cmd cmd;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       dis_cmd_clear(&cmd);
+
+       cmd.proc_cmd = DIS_CMD_REQ_VIEWFINDER;
+       cmd.proc_reg0 = mode;   /* standby */
+
+       ret = __discam_excute_cmd(client, &cmd);
+       __check_ret_return(ret, -1, "__discam_excute_cmd err.\n");
+       __discam_check_cmd_retval_return(cmd);
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return ret;
+}
+
+static int __stop_viewfinder(struct i2c_client *client)
+{
+       int ret = 0;
+       struct dis_cmd cmd;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       dis_cmd_clear(&cmd);
+
+       cmd.proc_cmd = DIS_CMD_REQ_VIEWFINDER;
+       cmd.proc_reg0 = DIS_VIEWFINDER_STOP;    /* standby */
+
+       ret = __discam_excute_cmd(client, &cmd);
+       __check_ret_return(ret, -1, "__discam_excute_cmd err.\n");
+       __discam_check_cmd_retval_return(cmd);
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return ret;
+}
+
+static int __req_snapshot(struct i2c_client *client, __u8 mode)
+{
+       int ret = 0;
+       struct dis_cmd cmd;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       dis_cmd_clear(&cmd);
+
+       cmd.proc_cmd = DIS_CMD_REQ_SNAPSHOT;
+       cmd.proc_reg0 = mode;
+
+       ret = __discam_excute_cmd(client, &cmd);
+       __check_ret_return(ret, -1, "__discam_excute_cmd err.\n");
+       __discam_check_cmd_retval_return(cmd);
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return ret;
+}
+
+/* if address or data is 8 bit, set MSB to 0 */
+static int __write_sensor_register(struct i2c_client *client,
+                                  __u16 addr, __u8 data)
+{
+       int ret = 0;
+       struct dis_cmd cmd;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       dis_cmd_clear(&cmd);
+
+       cmd.proc_cmd = DIS_CMD_W_SENSOR_REG;
+       cmd.proc_reg0 = (__u8) (addr >> 8);
+       cmd.proc_reg1 = (__u8) (addr);
+       cmd.proc_reg3 = (__u8) (data);
+
+       __discam_dbg(DBG_LEVEL_2, "write 0x%x to 0x%x.\n", data, addr);
+
+       ret = __discam_excute_cmd(client, &cmd);
+       __check_ret_return(ret, -1, "__discam_excute_cmd err.\n");
+       __discam_check_cmd_retval_return(cmd);
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return ret;
+}
+
+/* only 8 bit data supported now */
+static int __read_sensor_register(struct i2c_client *client,
+                                 __u16 addr, __u8 *data)
+{
+       int ret = 0;
+       struct dis_cmd cmd;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       dis_cmd_clear(&cmd);
+
+       cmd.proc_cmd = DIS_CMD_R_SENSOR_REG;
+       cmd.proc_reg0 = (__u8) (addr >> 8);
+       cmd.proc_reg1 = (__u8) (addr);
+
+       ret = __discam_excute_cmd(client, &cmd);
+       __check_ret_return(ret, -1, "__discam_excute_cmd err.\n");
+       __discam_check_cmd_retval_return(cmd);
+
+       (*data) = cmd.ret_reg3;
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return ret;
+}
+
+/* if address is 8 bit, set MSB to 0, only support 8bit data */
+static int __write_register(struct i2c_client *client, __u16 addr, __u8 data)
+{
+       int ret = 0;
+       struct dis_cmd cmd;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       dis_cmd_clear(&cmd);
+
+       cmd.proc_cmd = DIS_CMD_W_REG;
+       cmd.proc_reg0 = (__u8) (addr >> 8);
+       cmd.proc_reg1 = (__u8) (addr);
+       cmd.proc_reg3 = (__u8) (data);
+
+       ret = __discam_excute_cmd(client, &cmd);
+       __check_ret_return(ret, -1, "__discam_excute_cmd err.\n");
+       __discam_check_cmd_retval_return(cmd);
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return ret;
+}
+
+/* only 8 bit data supported now */
+static int __read_register(struct i2c_client *client, __u16 addr, __u8 * data)
+{
+       int ret = 0;
+       struct dis_cmd cmd;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       dis_cmd_clear(&cmd);
+
+       cmd.proc_cmd = DIS_CMD_R_REG;
+       cmd.proc_reg0 = (__u8) (addr >> 8);
+       cmd.proc_reg1 = (__u8) (addr);
+
+       ret = __discam_excute_cmd(client, &cmd);
+       __check_ret_return(ret, -1, "__discam_excute_cmd err.\n");
+       __discam_check_cmd_retval_return(cmd);
+
+       (*data) = cmd.ret_reg3;
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return ret;
+}
+
+/*
+ * DIS-AN10-1003:
+ *
+ * Integration time given in 100us.
+ * A range from 100us (1/10000s) up to 6,5s is possible.
+ * A value of 0 returns DIS_CMD_WRONG_PARAMETER and does not chagne
+ *     actual setting.
+ */
+static int __set_itg_time(struct i2c_client *client,
+                         __u16 time, __u32 *actual_time)
+{
+       int ret = 0;
+       struct dis_cmd cmd;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       dis_cmd_clear(&cmd);
+
+       /* NOTE: aussme the sensor clock is 19.28 MHZ */
+       /* time = (int)(time * 4800 / 1928); */
+
+       cmd.proc_cmd = DIS_CMD_REQ_ITG_TIME;
+       cmd.proc_reg0 = (__u8) ((time) >> 8);   /* MSB */
+       cmd.proc_reg1 = (__u8) (time);
+
+       __discam_dbg(DBG_LEVEL_2, "time = %d\n", time);
+
+       ret = __discam_excute_cmd(client, &cmd);
+       __check_ret_return(ret, -1, "__discam_excute_cmd err.\n");
+       __discam_check_cmd_retval_return(cmd);
+
+       (*actual_time) = (((__u32) cmd.ret_reg1) << 16) |
+           (((__u32) cmd.ret_reg2) << 8) | ((__u32) cmd.ret_reg3);
+
+       __discam_dbg(DBG_LEVEL_2, "actual time = %d\n", (*actual_time));
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return ret;
+}
+
+/*
+ * DIS-AN10-1003:
+ *
+ * if an illegal ISO speed value (>1600) is requested,
+ * DIS_CMD_WRONG_PARAMETER is returned.
+ */
+static int __set_iso(struct i2c_client *client, __u16 iso, __u16 * actual_iso)
+{
+       int ret = 0;
+       struct dis_cmd cmd;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       dis_cmd_clear(&cmd);
+
+       cmd.proc_cmd = DIS_CMD_REQ_ISO_SPEED;
+       cmd.proc_reg0 = ((iso) >> 8);   /* MSB */
+       cmd.proc_reg1 = (__u8) iso;
+
+       __discam_dbg(DBG_LEVEL_2, "iso = %d\n", iso);
+
+       ret = __discam_excute_cmd(client, &cmd);
+       __check_ret_return(ret, -1, "__discam_excute_cmd err.\n");
+       __discam_check_cmd_retval_return(cmd);
+
+       (*actual_iso) = (((__u16) cmd.ret_reg1) << 8) | ((__u16) cmd.ret_reg2);
+
+       __discam_dbg(DBG_LEVEL_2, "actual iso = %d\n", (*actual_iso));
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return ret;
+}
+
+/*
+ * DIS-AN10-1003:
+ *
+ * set aperture opening factor.
+ *
+ * 0 - closed (0%)
+ * .
+ * 25 - F#5.6 (25%)
+ * .
+ * 100 - open (100%)
+ */
+static int __set_aperture_pos(struct i2c_client *client, __u8 factor)
+{
+       int ret = 0;
+       struct dis_cmd cmd;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       dis_cmd_clear(&cmd);
+
+       cmd.proc_cmd = DIS_CMD_SET_APERTURE_POS;
+       cmd.proc_reg0 = factor;
+
+       __discam_dbg(DBG_LEVEL_2, "aperture factor = %d\n", factor);
+
+       ret = __discam_excute_cmd(client, &cmd);
+       __check_ret_return(ret, -1, "__discam_excute_cmd err.\n");
+       __discam_check_cmd_retval_return(cmd);
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return ret;
+}
+
+static int __get_aperture_pos(struct i2c_client *client, __u8 * factor)
+{
+       int ret = 0;
+       struct dis_cmd cmd;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       dis_cmd_clear(&cmd);
+
+       cmd.proc_cmd = DIS_CMD_GET_APERTURE_POS;
+
+       ret = __discam_excute_cmd(client, &cmd);
+       __check_ret_return(ret, -1, "__discam_excute_cmd err.\n");
+       __discam_check_cmd_retval_return(cmd);
+
+       (*factor) = cmd.ret_reg1;
+
+       __discam_dbg(DBG_LEVEL_1, "aperture factor = %d\n", *factor);
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return ret;
+}
+
+/*
+ * DIS-AN10-1003:
+ *
+ * get actual exposure setting
+ *
+ * integration time is given in 100/256 us steps
+ */
+static int __get_exposure_setting(struct i2c_client *client,
+                                 __u32 *time, __u16 *iso, __u8 *aperture)
+{
+       int ret = 0;
+       struct dis_cmd cmd;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       dis_cmd_clear(&cmd);
+
+       cmd.proc_cmd = DIS_CMD_GET_EXPOSURE_SETTING;
+       cmd.proc_reg0 = 0x00;
+
+       ret = __discam_excute_cmd(client, &cmd);
+       __check_ret_return(ret, -1, "__discam_excute_cmd err.\n");
+       __discam_check_cmd_retval_return(cmd);
+
+       (*time) = (((__u32) cmd.ret_reg1) << 16) |
+           (((__u32) cmd.ret_reg2) << 8) | ((__u32) cmd.ret_reg3);
+
+       dis_cmd_clear(&cmd);
+
+       cmd.proc_cmd = DIS_CMD_GET_EXPOSURE_SETTING;
+       cmd.proc_reg0 = 0x01;
+
+       ret = __discam_excute_cmd(client, &cmd);
+       __check_ret_return(ret, -1, "__discam_excute_cmd err.\n");
+       __discam_check_cmd_retval_return(cmd);
+
+       (*iso) = (((__u16) cmd.ret_reg1) << 8) | ((__u16) cmd.ret_reg2);
+
+       dis_cmd_clear(&cmd);
+
+       cmd.proc_cmd = DIS_CMD_GET_EXPOSURE_SETTING;
+       cmd.proc_reg0 = 0x05;
+
+       ret = __discam_excute_cmd(client, &cmd);
+       __check_ret_return(ret, -1, "__discam_excute_cmd err.\n");
+       __discam_check_cmd_retval_return(cmd);
+
+       (*aperture) = cmd.ret_reg1;
+
+       __discam_dbg(DBG_LEVEL_1, "time = %d, iso = %d, aperture = %d\n",
+               (*time), *iso, *aperture);
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return ret;
+}
+
+/*
+ * DIS-AN10-1003:
+ *
+ * get last exposure setting
+ *
+ * integration time is given in 100/256 us steps
+ */
+static int __get_last_exposure_setting(struct i2c_client *client,
+                                      __u32 *time, __u16 *iso,
+                                      __u8 *aperture)
+{
+       int ret = 0;
+       struct dis_cmd cmd;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       dis_cmd_clear(&cmd);
+
+       cmd.proc_cmd = DIS_CMD_GET_EXPOSURE_SETTING;
+       cmd.proc_reg0 = 0x10;
+
+       ret = __discam_excute_cmd(client, &cmd);
+       __check_ret_return(ret, -1, "__discam_excute_cmd err.\n");
+       __discam_check_cmd_retval_return(cmd);
+
+       (*time) = (((__u32) cmd.ret_reg1) << 16) |
+           (((__u32) cmd.ret_reg2) << 8) | ((__u32) cmd.ret_reg3);
+
+       dis_cmd_clear(&cmd);
+
+       cmd.proc_cmd = DIS_CMD_GET_EXPOSURE_SETTING;
+       cmd.proc_reg0 = 0x11;
+
+       ret = __discam_excute_cmd(client, &cmd);
+       __check_ret_return(ret, -1, "__discam_excute_cmd err.\n");
+       __discam_check_cmd_retval_return(cmd);
+
+       (*iso) = (((__u16) cmd.ret_reg1) << 8) | ((__u16) cmd.ret_reg2);
+
+       dis_cmd_clear(&cmd);
+
+       cmd.proc_cmd = DIS_CMD_GET_EXPOSURE_SETTING;
+       cmd.proc_reg0 = 0x15;
+
+       ret = __discam_excute_cmd(client, &cmd);
+       __check_ret_return(ret, -1, "__discam_excute_cmd err.\n");
+       __discam_check_cmd_retval_return(cmd);
+
+       (*aperture) = cmd.ret_reg1;
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return ret;
+}
+
+static int __enable_snapshot_shutter(struct i2c_client *client)
+{
+       int ret = 0;
+       struct dis_cmd cmd;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       dis_cmd_clear(&cmd);
+
+       cmd.proc_cmd = DIS_CMD_REQ_SHUTTER_USAGE;
+       cmd.proc_reg0 = 0x00;   /* enable */
+
+       ret = __discam_excute_cmd(client, &cmd);
+       __check_ret_return(ret, -1, "__discam_excute_cmd err.\n");
+       __discam_check_cmd_retval_return(cmd);
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return ret;
+}
+
+static int __disable_snapshot_shutter(struct i2c_client *client)
+{
+       int ret = 0;
+       struct dis_cmd cmd;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       dis_cmd_clear(&cmd);
+
+       cmd.proc_cmd = DIS_CMD_REQ_SHUTTER_USAGE;
+       cmd.proc_reg0 = 0x01;   /* disable */
+
+       ret = __discam_excute_cmd(client, &cmd);
+       __check_ret_return(ret, -1, "__discam_excute_cmd err.\n");
+       __discam_check_cmd_retval_return(cmd);
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+static int __config_snapshot_param_vf(struct i2c_client *client)
+{
+       int ret = 0;
+       struct dis_cmd cmd;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       dis_cmd_clear(&cmd);
+
+       cmd.proc_cmd = DIS_CMD_CFG_SNAPSHOT_PARAM;
+       cmd.proc_reg0 = 0x00;   /* param usage */
+       cmd.proc_reg1 = 0x00;   /* use vf param */
+
+       ret = __discam_excute_cmd(client, &cmd);
+       __check_ret_return(ret, -1, "__discam_excute_cmd err.\n");
+       __discam_check_cmd_retval_return(cmd);
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+static int __config_snapshot_param_manual(struct i2c_client *client,
+                                         __u16 itg_time, __u16 iso,
+                                         __u8 aperture)
+{
+       int ret = 0;
+       struct dis_cmd cmd;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       dis_cmd_clear(&cmd);
+
+       __discam_dbg(DBG_LEVEL_1, "time = %d, iso = %d, aperture = %d\n",
+               itg_time, iso, aperture);
+
+       cmd.proc_cmd = DIS_CMD_CFG_SNAPSHOT_PARAM;
+       cmd.proc_reg0 = 0x00;   /* param usage */
+       cmd.proc_reg1 = 0x01;   /* use vf param */
+
+       ret = __discam_excute_cmd(client, &cmd);
+       __check_ret_return(ret, -1, "__discam_excute_cmd err.\n");
+       __discam_check_cmd_retval_return(cmd);
+
+       /* config itg time */
+       cmd.proc_cmd = DIS_CMD_CFG_SNAPSHOT_PARAM;
+       cmd.proc_reg0 = 0x01;
+       cmd.proc_reg1 = (__u8) (itg_time >> 8);
+       cmd.proc_reg2 = (__u8) itg_time;
+
+       ret = __discam_excute_cmd(client, &cmd);
+       __check_ret_return(ret, -1, "__discam_excute_cmd err.\n");
+       __discam_check_cmd_retval_return(cmd);
+
+       cmd.proc_cmd = DIS_CMD_CFG_SNAPSHOT_PARAM;
+       cmd.proc_reg0 = 0x02;
+       cmd.proc_reg1 = (__u8) (iso >> 8);
+       cmd.proc_reg2 = (__u8) iso;
+
+       ret = __discam_excute_cmd(client, &cmd);
+       __check_ret_return(ret, -1, "__discam_excute_cmd err.\n");
+       __discam_check_cmd_retval_return(cmd);
+
+       cmd.proc_cmd = DIS_CMD_CFG_SNAPSHOT_PARAM;
+       cmd.proc_reg0 = 0x06;
+       cmd.proc_reg1 = aperture;
+
+       ret = __discam_excute_cmd(client, &cmd);
+       __check_ret_return(ret, -1, "__discam_excute_cmd err.\n");
+       __discam_check_cmd_retval_return(cmd);
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+/*
+ * Auto Focus commands
+ */
+static int __req_focus_pos(struct i2c_client *client, __u16 pos)
+{
+       int ret = 0;
+       struct dis_cmd cmd;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       dis_cmd_clear(&cmd);
+
+       cmd.proc_cmd = DIS_CMD_REQ_FOCUS_POS;
+       cmd.proc_reg0 = (__u8) (pos >> 8);
+       cmd.proc_reg1 = (__u8) (pos);
+
+       ret = __discam_excute_cmd(client, &cmd);
+       __check_ret_return(ret, -1, "__discam_excute_cmd err.\n");
+       __discam_check_cmd_retval_return(cmd);
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+static int __get_af_status(struct i2c_client *client,
+                          __u8 *status, __u16 *pos)
+{
+       int ret = 0;
+       struct dis_cmd cmd;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       dis_cmd_clear(&cmd);
+
+       cmd.proc_cmd = DIS_CMD_GET_AFSTATUS;
+
+       ret = __discam_excute_cmd(client, &cmd);
+       __check_ret_return(ret, -1, "__discam_excute_cmd err.\n");
+       __discam_check_cmd_retval_return(cmd);
+
+       (*status) = cmd.ret_reg1;
+       (*pos) = (((__u16) cmd.ret_reg1) << 8) | ((__u16) cmd.ret_reg2);
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+static int __cfg_auto_focus(struct i2c_client *client, int internal)
+{
+       int ret = 0;
+       struct dis_cmd cmd;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       dis_cmd_clear(&cmd);
+
+       cmd.proc_cmd = DIS_CMD_CFG_AUTO_FOCUS;
+       cmd.proc_reg0 = 0x00;
+       cmd.proc_reg1 = (internal ? 0x01 : 0x00);
+
+       ret = __discam_excute_cmd(client, &cmd);
+       __check_ret_return(ret, -1, "__discam_excute_cmd err.\n");
+       __discam_check_cmd_retval_return(cmd);
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+static int __cfg_focus_range(struct i2c_client *client, __u8 range)
+{
+       int ret = 0;
+       struct dis_cmd cmd;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       dis_cmd_clear(&cmd);
+
+       cmd.proc_cmd = DIS_CMD_CFG_AUTO_FOCUS;
+       cmd.proc_reg0 = 0x06;
+       cmd.proc_reg1 = range;
+
+       ret = __discam_excute_cmd(client, &cmd);
+       __check_ret_return(ret, -1, "__discam_excute_cmd err.\n");
+       __discam_check_cmd_retval_return(cmd);
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+static int __req_auto_focus(struct i2c_client *client, __u32 sharpness)
+{
+       int ret = 0;
+       struct dis_cmd cmd;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       dis_cmd_clear(&cmd);
+
+       cmd.proc_cmd = DIS_CMD_REQ_AUTO_FOCUS;
+       cmd.proc_reg0 = (__u8) (sharpness >> 24);
+       cmd.proc_reg1 = (__u8) (sharpness >> 16);
+       cmd.proc_reg2 = (__u8) (sharpness >> 8);
+       cmd.proc_reg2 = (__u8) (sharpness);
+
+       ret = __discam_excute_cmd(client, &cmd);
+       __check_ret_return(ret, -1, "__discam_excute_cmd err.\n");
+       __discam_check_cmd_retval_return(cmd);
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+static int __req_stop_auto_focus(struct i2c_client *client)
+{
+       int ret = 0;
+       struct dis_cmd cmd;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       dis_cmd_clear(&cmd);
+
+       cmd.proc_cmd = DIS_CMD_REQ_STOP_AUTO_FOCUS;
+
+       ret = __discam_excute_cmd(client, &cmd);
+       __check_ret_return(ret, -1, "__discam_excute_cmd err.\n");
+       __discam_check_cmd_retval_return(cmd);
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+/*
+ * helper functions to get mode according to resolution.
+ *
+ * FIXME:
+ *
+ * add code to deal with in case no resolution is matched.
+ * ex: for 14MP, ISP use resolution 4352*3264, but sensor output 4416*3312
+ */
+static int __get_vf_fmt_idx(unsigned int width, unsigned int height)
+{
+       int i;
+
+       for (i = 0; i < g_this_camera->fmt_nr; i++) {
+               if (g_this_camera->fmts[i].mode != DIS_VIEWFINDER_MODE)
+                       continue;
+               if (g_this_camera->fmts[i].s_fmt.v4l2_fmt.fmt.pix.width !=
+                   width)
+                       continue;
+               if (g_this_camera->fmts[i].s_fmt.v4l2_fmt.fmt.pix.height !=
+                   height)
+                       continue;
+
+               return i;
+       }
+
+       return -1;
+}
+
+static int __get_ss_fmt_idx(unsigned int width, unsigned int height)
+{
+       int i;
+
+       for (i = 0; i < g_this_camera->fmt_nr; i++) {
+               if (g_this_camera->fmts[i].mode != DIS_SNAPSHOT_MODE)
+                       continue;
+               if (g_this_camera->fmts[i].s_fmt.v4l2_fmt.fmt.pix.width !=
+                   width)
+                       continue;
+               if (g_this_camera->fmts[i].s_fmt.v4l2_fmt.fmt.pix.height !=
+                   height)
+                       continue;
+
+               return i;
+       }
+
+       return -1;
+}
+
+static int __set_mipi_lane(struct i2c_client *client,
+                          unsigned int num)
+{
+       int ret = 0;
+
+       __discam_dbg(2, "enter...\n");
+       __discam_dbg(2, "MIPI lane %d\n", num);
+
+       ret = __write_sensor_register(client, 0x3200, 0);
+       ret += __write_sensor_register(client, 0x3212, 0);
+       switch (num) {
+       case 4:
+               ret += __write_sensor_register(client, 0x3003, 0xA);
+               ret += __write_sensor_register(client, 0x3006, 0x8A);
+               ret += __write_sensor_register(client, 0x3106, 0x05);
+               break;
+       case 1:
+               ret += __write_sensor_register(client, 0x3003, 0x8);
+               ret += __write_sensor_register(client, 0x3006, 0xAA);
+               ret += __write_sensor_register(client, 0x3106, 0x09);
+               break;
+       default: /* default 2 lane */
+               ret += __write_sensor_register(client, 0x3003, 0x9);
+               ret += __write_sensor_register(client, 0x3006, 0xAA);
+               ret += __write_sensor_register(client, 0x3106, 0x05);
+               break;
+       }
+
+       ret += __write_sensor_register(client, 0x3212, 0x10);
+       ret += __write_sensor_register(client, 0x3212, 0xA0);
+
+       __discam_dbg(2, "leave...\n");
+       return ret;
+}
+
+__u8 discam_set_mipi_lane(struct v4l2_subdev *sd,
+                         unsigned int lane_num)
+{
+       struct i2c_client *client;
+       struct discam_device *dev;
+       int ret = 0;
+
+       __discam_dbg(1, "enter...\n");
+
+       __check_dev_null_return(sd, -EINVAL);
+
+       dev = to_discam_device(sd);
+       client = v4l2_get_subdevdata(sd);
+
+       if (dev->status == DIS_STATUS_POWER_DOWN) {
+               __discam_warn("startup.\n");
+               ret = discam_startup(sd);
+               __check_ret_return(ret, -1, "startup err.\n");
+       }
+
+       if (dev->status == DIS_STATUS_STANDBY) {
+               ret = discam_wakeup(sd);
+               __check_ret_return(ret, -1, "discam_wakeup err.\n");
+       }
+
+       ret = __set_mipi_lane(client, lane_num);
+       __check_ret_return(ret, -1, "__set_mipi_lane err.\n");
+
+       __discam_dbg(1, "leave...\n");
+
+       return 0;
+}
+
+__u8 discam_get_vf_mode(unsigned int width, unsigned int height)
+{
+       __u8 mode = g_this_camera->default_vf_mode;
+       int i = __get_vf_fmt_idx(width, height);
+
+       if (i >= 0)
+               mode = g_this_camera->fmts[i].modeval;
+
+       return mode;
+}
+
+__u8 discam_get_ss_mode(unsigned int width, unsigned int height)
+{
+       __u8 mode = g_this_camera->default_ss_mode;
+       int i = __get_ss_fmt_idx(width, height);
+
+       if (i >= 0)
+               mode = g_this_camera->fmts[i].modeval;
+
+       return mode;
+}
+
+/*
+ * functions expose to outside.
+ */
+int discam_startup(struct v4l2_subdev *sd)
+{
+       struct i2c_client *client;
+       struct discam_device *dev;
+       int ret = 0;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       __check_dev_null_return(sd, -EINVAL);
+
+       dev = to_discam_device(sd);
+       client = v4l2_get_subdevdata(sd);
+
+       if (dev->status != DIS_STATUS_POWER_DOWN) {
+               __discam_warn("device alreay started up.\n");
+               return 0;
+       }
+
+       ret = __startup(client);
+       __check_ret_return(ret, -1, "__startup err.\n");
+
+       dev->status = DIS_STATUS_ACTIVE;
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+int discam_get_fw_version(struct v4l2_subdev *sd,
+                         __u8 *version, __u16 *revision)
+{
+       struct i2c_client *client;
+       struct discam_device *dev;
+       int ret = 0;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       __check_dev_null_return(sd, -EINVAL);
+
+       dev = to_discam_device(sd);
+       client = v4l2_get_subdevdata(sd);
+
+       /*
+        * DIS_CMD_GET_VERSION can be called after
+        * start-up and initialization
+        */
+       if (dev->status == DIS_STATUS_POWER_DOWN) {
+               ret = discam_startup(sd);
+               __check_ret_return(ret, -1, "discam_startup err.\n");
+       }
+
+       ret = __get_fw_version(client, version, revision);
+       __check_ret_return(ret, -1, "__get_fw_version err.\n");
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+int discam_get_sensor_version(struct v4l2_subdev *sd,
+                             __u16 *id, __u8 *revision)
+{
+       struct i2c_client *client;
+       struct discam_device *dev;
+       int ret = 0;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       __check_dev_null_return(sd, -EINVAL);
+
+       dev = to_discam_device(sd);
+       client = v4l2_get_subdevdata(sd);
+
+       /*
+        * DIS_CMD_GET_VERSION can be called after
+        * start-up and initialization
+        */
+       if (dev->status == DIS_STATUS_POWER_DOWN) {
+               ret = discam_startup(sd);
+               __check_ret_return(ret, -1, "discam_startup err.\n");
+       }
+
+       ret = __get_sensor_version(client, id, revision);
+       __check_ret_return(ret, -1, "__get_fw_version err.\n");
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+int discam_power_down(struct v4l2_subdev *sd)
+{
+       struct i2c_client *client;
+       struct discam_device *dev;
+       int ret = 0;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       __check_dev_null_return(sd, -EINVAL);
+
+       dev = to_discam_device(sd);
+       client = v4l2_get_subdevdata(sd);
+
+       /*
+        * FIXME:
+        * if in viewfinder mode, stop viewfinder first
+        * From DIS: not required.
+        *
+        * still put the code here for sure.
+        * anyway, it will have no nagtive impact.
+        */
+       if (dev->status == DIS_STATUS_VIEWFINDER) {
+               __discam_warn("stop viewfinder.\n");
+               ret = discam_stop_viewfinder(sd);
+               __check_ret_return(ret, -1, "stop viewfinder err.\n");
+       }
+
+       if (dev->status == DIS_STATUS_POWER_DOWN) {
+               __discam_warn("already power off.\n");
+               return 0;
+       }
+
+       ret = __power_down(client);
+       __check_ret_return(ret, -1, "__power_down err.\n");
+
+       dev->status = DIS_STATUS_POWER_DOWN;
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+int discam_standby(struct v4l2_subdev *sd)
+{
+       struct i2c_client *client;
+       struct discam_device *dev;
+       int ret = 0;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       __check_dev_null_return(sd, -EINVAL);
+
+       dev = to_discam_device(sd);
+       client = v4l2_get_subdevdata(sd);
+
+       /*
+        * FIXME:
+        * not sure if can standby from viewfinder mode directly ?
+        *
+        * DIS: yes
+        *
+        * still put the code here for sure.
+        * anyway, it will have no nagtive impact.
+        */
+       if (dev->status == DIS_STATUS_VIEWFINDER) {
+               __discam_warn("stop viewfinder.\n");
+               ret = discam_stop_viewfinder(sd);
+               __check_ret_return(ret, -1, "stop viewfinder err.\n");
+       }
+
+       /* if current status is power down, init it first */
+       if (dev->status == DIS_STATUS_POWER_DOWN) {
+               __discam_warn("startup.\n");
+               ret = discam_startup(sd);
+               __check_ret_return(ret, -1, "startup err.\n");
+       }
+
+       if (dev->status == DIS_STATUS_STANDBY) {
+               __discam_warn("already standby.\n");
+               return 0;
+       }
+
+       ret = __standby(client);
+       __check_ret_return(ret, -1, "__standby err.\n");
+
+       dev->status = DIS_STATUS_STANDBY;
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+int discam_wakeup(struct v4l2_subdev *sd)
+{
+       struct i2c_client *client;
+       struct discam_device *dev;
+       int ret = 0;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       __check_dev_null_return(sd, -EINVAL);
+
+       dev = to_discam_device(sd);
+       client = v4l2_get_subdevdata(sd);
+
+       /* if current status is power down, init it first */
+       if (dev->status == DIS_STATUS_POWER_DOWN) {
+               __discam_warn("startup.\n");
+               ret = discam_startup(sd);
+               __check_ret_return(ret, -1, "startup err.\n");
+       }
+
+       if (dev->status != DIS_STATUS_STANDBY) {
+               __discam_warn("not in standby mode, just return.\n");
+               return 0;
+       }
+
+       ret = __wakeup(client);
+       __check_ret_return(ret, -1, "__wakeup err.\n");
+
+       dev->status = DIS_STATUS_ACTIVE;
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+int discam_write_sensor_register(struct v4l2_subdev *sd, __u16 addr, __u8 data)
+{
+       struct i2c_client *client;
+       struct discam_device *dev;
+       int ret = 0;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       __check_dev_null_return(sd, -EINVAL);
+
+       dev = to_discam_device(sd);
+       client = v4l2_get_subdevdata(sd);
+
+       /*
+        * need wake up status ?
+        *
+        * DIS: yes
+        */
+       ret = discam_wakeup(sd);
+       __check_ret_return(ret, -1, "discam_wakeup err.\n");
+
+       ret = __write_sensor_register(client, addr, data);
+       __check_ret_return(ret, -1, "__write_sensor_register err.\n");
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+int discam_read_sensor_register(struct v4l2_subdev *sd, __u16 addr, __u8 * data)
+{
+       struct i2c_client *client;
+       struct discam_device *dev;
+       int ret = 0;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       __check_dev_null_return(sd, -EINVAL);
+
+       dev = to_discam_device(sd);
+       client = v4l2_get_subdevdata(sd);
+
+       /*
+        * need wake up status ?
+        *
+        * DIS: yes
+        */
+       ret = discam_wakeup(sd);
+       __check_ret_return(ret, -1, "discam_wakeup err.\n");
+
+       ret = __read_sensor_register(client, addr, data);
+       __check_ret_return(ret, -1, "__read_sensor_register err.\n");
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+int discam_write_register(struct v4l2_subdev *sd, __u16 addr, __u8 data)
+{
+       struct i2c_client *client;
+       struct discam_device *dev;
+       int ret = 0;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       __check_dev_null_return(sd, -EINVAL);
+
+       dev = to_discam_device(sd);
+       client = v4l2_get_subdevdata(sd);
+
+       /*
+        * need wake up status ?
+        *
+        * DIS: yes
+        */
+       ret = discam_wakeup(sd);
+       __check_ret_return(ret, -1, "discam_wakeup err.\n");
+
+       ret = __write_register(client, addr, data);
+       __check_ret_return(ret, -1, "__write_register err.\n");
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+int discam_read_register(struct v4l2_subdev *sd, __u16 addr, __u8 * data)
+{
+       struct i2c_client *client;
+       struct discam_device *dev;
+       int ret = 0;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       __check_dev_null_return(sd, -EINVAL);
+
+       dev = to_discam_device(sd);
+       client = v4l2_get_subdevdata(sd);
+
+       /*
+        * need wake up status ?
+        *
+        * DIS: yes
+        */
+       ret = discam_wakeup(sd);
+       __check_ret_return(ret, -1, "discam_wakeup err.\n");
+
+       ret = __read_register(client, addr, data);
+       __check_ret_return(ret, -1, "__read_register err.\n");
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+static int __discam_s_exposure(struct v4l2_subdev *sd, __u32 val);
+static int __discam_s_iso(struct v4l2_subdev *sd, __u32 val);
+static int __discam_s_aperture(struct v4l2_subdev *sd, __u32 val);
+int discam_start_viewfinder(struct v4l2_subdev *sd, __u8 mode)
+{
+       struct i2c_client *client;
+       struct discam_device *dev;
+       int ret = 0;
+       __u8 act_mode;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       __check_dev_null_return(sd, -EINVAL);
+
+       dev = to_discam_device(sd);
+       client = v4l2_get_subdevdata(sd);
+
+       __discam_s_exposure(sd, (int)(500));
+       __discam_s_iso(sd, 80);
+       __discam_s_aperture(sd, 100);
+
+       /*
+        * after discam_startup, the camera is in DIS_STATUS_ACTIVE mode.
+        */
+       if (dev->status == DIS_STATUS_POWER_DOWN) {
+               __discam_warn("startup.\n");
+               ret = discam_startup(sd);
+               __check_ret_return(ret, -1, "startup err.\n");
+       }
+
+       /*
+        * if in DIS_STATUS_STANDBY mode, we need to wakeup first.
+        */
+       if (dev->status == DIS_STATUS_STANDBY) {
+               ret = discam_wakeup(sd);
+               __check_ret_return(ret, -1, "discam_wakeup err.\n");
+       }
+
+       __discam_dbg(DBG_LEVEL_1, "mode passed in is 0x%x\n", mode);
+
+       /* really do start viewfinder */
+       if (!__get_vf_format(mode)) {
+               __discam_err("unknown viewfinder mode: 0x%x\n", mode);
+               __discam_err("use default mode: 0x%x\n",
+                            g_this_camera->default_vf_mode);
+               act_mode = g_this_camera->default_vf_mode;
+       } else
+               act_mode = mode;
+
+       __discam_dbg(DBG_LEVEL_1,
+               "actual mode to be start is 0x%x\n", act_mode);
+
+       if (dev->status == DIS_STATUS_VIEWFINDER) {
+               __discam_warn("already in viewfinder mode 0x%x.\n",
+                             dev->cur_vf_mode);
+               if (act_mode == dev->cur_vf_mode) {
+                       __discam_dbg(DBG_LEVEL_1,
+                               "already in mode 0x%x, just return.\n",
+                               dev->cur_vf_mode);
+                       return 0;
+               } else {
+                       __discam_dbg(DBG_LEVEL_1,
+                       "need change mode to 0x%x,stop vf first.\n",
+                       act_mode);
+                       discam_stop_viewfinder(sd);
+               }
+       }
+
+       ret = __start_viewfinder(client, act_mode);
+       __check_ret_return(ret, -1, "__start_viewfinder err.\n");
+
+       dev->status = DIS_STATUS_VIEWFINDER;
+       dev->cur_vf_mode = act_mode;
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+int discam_stop_viewfinder(struct v4l2_subdev *sd)
+{
+       struct i2c_client *client;
+       struct discam_device *dev;
+       int ret = 0;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       __check_dev_null_return(sd, -EINVAL);
+
+       dev = to_discam_device(sd);
+       client = v4l2_get_subdevdata(sd);
+
+       if (dev->status != DIS_STATUS_VIEWFINDER) {
+               __discam_warn("already stopped viewfinder.\n");
+               return 0;
+       }
+
+       ret = __stop_viewfinder(client);
+       __check_ret_return(ret, -1, "__stop_viewfinder err.\n");
+
+       dev->status = DIS_STATUS_ACTIVE;
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+int discam_req_snapshot(struct v4l2_subdev *sd, __u8 mode)
+{
+       struct i2c_client *client;
+       struct discam_device *dev;
+       int ret = 0;
+       __u8 act_mode;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       __check_dev_null_return(sd, -EINVAL);
+
+       dev = to_discam_device(sd);
+       client = v4l2_get_subdevdata(sd);
+
+       /*
+        * requestSnapshot can be called directly after init,
+        * no power down, standby or reset operations are needed.
+        */
+       if (dev->status == DIS_STATUS_POWER_DOWN) {
+               __discam_warn("startup.\n");
+               ret = discam_startup(sd);
+               __check_ret_return(ret, -1, "startup err.\n");
+       }
+
+       if (dev->status == DIS_STATUS_STANDBY) {
+               ret = discam_wakeup(sd);
+               __check_ret_return(ret, -1, "discam_wakeup err.\n");
+       }
+
+       /* really do snapshot */
+       if (!__get_ss_format(mode)) {
+               __discam_err("unknown snpshot mode: 0x%x\n", mode);
+               __discam_err("use default mode: 0x%x\n",
+                            g_this_camera->default_ss_mode);
+               act_mode = g_this_camera->default_ss_mode;
+       } else
+               act_mode = mode;
+
+       ret = __req_snapshot(client, act_mode);
+       __check_ret_return(ret, -1, "__req_snapshot err.\n");
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+int discam_set_itg_time(struct v4l2_subdev *sd, __u16 time, __u32 * actual_time)
+{
+       struct i2c_client *client;
+       struct discam_device *dev;
+       int ret = 0;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       __check_dev_null_return(sd, -EINVAL);
+
+       dev = to_discam_device(sd);
+       client = v4l2_get_subdevdata(sd);
+
+       if (dev->status == DIS_STATUS_POWER_DOWN) {
+               __discam_warn("startup.\n");
+               ret = discam_startup(sd);
+               __check_ret_return(ret, -1, "startup err.\n");
+       }
+
+       if (dev->status == DIS_STATUS_STANDBY) {
+               ret = discam_wakeup(sd);
+               __check_ret_return(ret, -1, "discam_wakeup err.\n");
+       }
+
+       /*
+        * Add code to check time valid ?
+        */
+       ret = __set_itg_time(client, time, actual_time);
+       __check_ret_return(ret, -1, "__set_itg_time err.\n");
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+int discam_set_iso(struct v4l2_subdev *sd, __u16 iso, __u16 *actual_iso)
+{
+       struct i2c_client *client;
+       struct discam_device *dev;
+       int ret = 0;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       __check_dev_null_return(sd, -EINVAL);
+
+       dev = to_discam_device(sd);
+       client = v4l2_get_subdevdata(sd);
+
+       if (dev->status == DIS_STATUS_POWER_DOWN) {
+               __discam_warn("startup.\n");
+               ret = discam_startup(sd);
+               __check_ret_return(ret, -1, "startup err.\n");
+       }
+
+       if (dev->status == DIS_STATUS_STANDBY) {
+               ret = discam_wakeup(sd);
+               __check_ret_return(ret, -1, "discam_wakeup err.\n");
+       }
+
+       /*
+        * Add code to check iso valid ?
+        */
+       ret = __set_iso(client, iso, actual_iso);
+       __check_ret_return(ret, -1, "__set_iso err.\n");
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+int discam_set_aperture(struct v4l2_subdev *sd, __u8 aperture_factor)
+{
+       struct i2c_client *client;
+       struct discam_device *dev;
+       int ret = 0;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       __check_dev_null_return(sd, -EINVAL);
+
+       dev = to_discam_device(sd);
+       client = v4l2_get_subdevdata(sd);
+
+       if (dev->status == DIS_STATUS_POWER_DOWN) {
+               __discam_warn("startup.\n");
+               ret = discam_startup(sd);
+               __check_ret_return(ret, -1, "startup err.\n");
+       }
+
+       if (dev->status == DIS_STATUS_STANDBY) {
+               ret = discam_wakeup(sd);
+               __check_ret_return(ret, -1, "discam_wakeup err.\n");
+       }
+
+       /*
+        * Add code to check aperture_factor valid ?
+        */
+       ret = __set_aperture_pos(client, aperture_factor);
+       __check_ret_return(ret, -1, "__set_aperture_pos err.\n");
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+int discam_get_aperture(struct v4l2_subdev *sd, __u8 *aperture_factor)
+{
+       struct i2c_client *client;
+       struct discam_device *dev;
+       int ret = 0;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       __check_dev_null_return(sd, -EINVAL);
+
+       dev = to_discam_device(sd);
+       client = v4l2_get_subdevdata(sd);
+
+       if (dev->status == DIS_STATUS_STANDBY) {
+               ret = discam_wakeup(sd);
+               __check_ret_return(ret, -1, "discam_wakeup err.\n");
+       }
+
+       /*
+        * Add code to check aperture_factor valid ?
+        */
+       ret = __get_aperture_pos(client, aperture_factor);
+       __check_ret_return(ret, -1, "__get_aperture_pos err.\n");
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+int discam_get_exposure_setting(struct v4l2_subdev *sd,
+                               __u32 *itg_time, __u16 *iso,
+                               __u8 *aperture_factor)
+{
+       struct i2c_client *client;
+       struct discam_device *dev;
+       int ret = 0;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       __check_dev_null_return(sd, -EINVAL);
+
+       dev = to_discam_device(sd);
+       client = v4l2_get_subdevdata(sd);
+
+       if (dev->status == DIS_STATUS_POWER_DOWN) {
+               __discam_warn("startup.\n");
+               ret = discam_startup(sd);
+               __check_ret_return(ret, -1, "startup err.\n");
+       }
+
+       if (dev->status == DIS_STATUS_STANDBY) {
+               ret = discam_wakeup(sd);
+               __check_ret_return(ret, -1, "discam_wakeup err.\n");
+       }
+
+       /*
+        * Add code to check aperture_factor valid ?
+        */
+       ret = __get_exposure_setting(client, itg_time, iso, aperture_factor);
+       __check_ret_return(ret, -1, "__get_exposure_setting err.\n");
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+int discam_get_last_exposure_setting(struct v4l2_subdev *sd,
+                                    __u32 *itg_time, __u16 *iso,
+                                    __u8 *aperture_factor)
+{
+       struct i2c_client *client;
+       struct discam_device *dev;
+       int ret = 0;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       __check_dev_null_return(sd, -EINVAL);
+
+       dev = to_discam_device(sd);
+       client = v4l2_get_subdevdata(sd);
+
+       if (dev->status == DIS_STATUS_POWER_DOWN) {
+               __discam_warn("startup.\n");
+               ret = discam_startup(sd);
+               __check_ret_return(ret, -1, "startup err.\n");
+       }
+
+       if (dev->status == DIS_STATUS_STANDBY) {
+               ret = discam_wakeup(sd);
+               __check_ret_return(ret, -1, "discam_wakeup err.\n");
+       }
+
+       /*
+        * Add code to check aperture_factor valid ?
+        */
+       ret = __get_last_exposure_setting(client, itg_time, iso,
+                                         aperture_factor);
+       __check_ret_return(ret, -1, "__get_last_exposure_setting err.\n");
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+int discam_enable_snapshot_shutter(struct v4l2_subdev *sd)
+{
+       struct i2c_client *client;
+       struct discam_device *dev;
+       int ret = 0;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       __check_dev_null_return(sd, -EINVAL);
+
+       dev = to_discam_device(sd);
+       client = v4l2_get_subdevdata(sd);
+
+       if (dev->status == DIS_STATUS_POWER_DOWN) {
+               __discam_warn("startup.\n");
+               ret = discam_startup(sd);
+               __check_ret_return(ret, -1, "startup err.\n");
+       }
+
+       if (dev->status == DIS_STATUS_STANDBY) {
+               ret = discam_wakeup(sd);
+               __check_ret_return(ret, -1, "discam_wakeup err.\n");
+       }
+
+       /*
+        * Add code to check aperture_factor valid ?
+        */
+       ret = __enable_snapshot_shutter(client);
+       __check_ret_return(ret, -1, "__enable_snapshot_shutter err.\n");
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+int discam_disable_snapshot_shutter(struct v4l2_subdev *sd)
+{
+       struct i2c_client *client;
+       struct discam_device *dev;
+       int ret = 0;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       __check_dev_null_return(sd, -EINVAL);
+
+       dev = to_discam_device(sd);
+       client = v4l2_get_subdevdata(sd);
+
+       if (dev->status == DIS_STATUS_POWER_DOWN) {
+               __discam_warn("startup.\n");
+               ret = discam_startup(sd);
+               __check_ret_return(ret, -1, "startup err.\n");
+       }
+
+       if (dev->status == DIS_STATUS_STANDBY) {
+               ret = discam_wakeup(sd);
+               __check_ret_return(ret, -1, "discam_wakeup err.\n");
+       }
+
+       /*
+        * Add code to check aperture_factor valid ?
+        */
+       ret = __disable_snapshot_shutter(client);
+       __check_ret_return(ret, -1, "__disable_snapshot_shutter err.\n");
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+int discam_config_snapshot_param_vf(struct v4l2_subdev *sd)
+{
+       struct i2c_client *client;
+       struct discam_device *dev;
+       int ret = 0;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       __check_dev_null_return(sd, -EINVAL);
+
+       dev = to_discam_device(sd);
+       client = v4l2_get_subdevdata(sd);
+
+       if (dev->status == DIS_STATUS_POWER_DOWN) {
+               __discam_warn("startup.\n");
+               ret = discam_startup(sd);
+               __check_ret_return(ret, -1, "startup err.\n");
+       }
+
+       if (dev->status == DIS_STATUS_STANDBY) {
+               ret = discam_wakeup(sd);
+               __check_ret_return(ret, -1, "discam_wakeup err.\n");
+       }
+
+       /*
+        * Add code to check aperture_factor valid ?
+        */
+       ret = __config_snapshot_param_vf(client);
+       __check_ret_return(ret, -1, "__config_snapshot_param_vf err.\n");
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+int discam_config_snapshot_param_mannual(struct v4l2_subdev *sd,
+                                        __u16 itg_time, __u16 iso,
+                                        __u8 aperture_factor)
+{
+       struct i2c_client *client;
+       struct discam_device *dev;
+       int ret = 0;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       __check_dev_null_return(sd, -EINVAL);
+
+       dev = to_discam_device(sd);
+       client = v4l2_get_subdevdata(sd);
+
+       if (dev->status == DIS_STATUS_POWER_DOWN) {
+               __discam_warn("startup.\n");
+               ret = discam_startup(sd);
+               __check_ret_return(ret, -1, "startup err.\n");
+       }
+
+       if (dev->status == DIS_STATUS_STANDBY) {
+               ret = discam_wakeup(sd);
+               __check_ret_return(ret, -1, "discam_wakeup err.\n");
+       }
+
+       /*
+        * Add code to check aperture_factor valid ?
+        */
+       ret = __config_snapshot_param_manual(client,
+                                            itg_time, iso, aperture_factor);
+       __check_ret_return(ret, -1, "__config_snapshot_param_manual err.\n");
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+int discam_req_focus_pos(struct v4l2_subdev *sd, __u16 pos)
+{
+       struct i2c_client *client;
+       struct discam_device *dev;
+       int ret = 0;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       __check_dev_null_return(sd, -EINVAL);
+
+       dev = to_discam_device(sd);
+       client = v4l2_get_subdevdata(sd);
+
+       if (dev->status == DIS_STATUS_POWER_DOWN) {
+               __discam_warn("startup.\n");
+               ret = discam_startup(sd);
+               __check_ret_return(ret, -1, "startup err.\n");
+       }
+
+       /*
+        * need to wakeup sensor first ?
+        */
+       if (dev->status == DIS_STATUS_STANDBY) {
+               ret = discam_wakeup(sd);
+               __check_ret_return(ret, -1, "discam_wakeup err.\n");
+       }
+
+       /*
+        * Add code to check aperture_factor valid ?
+        */
+       ret = __req_focus_pos(client, pos);
+       __check_ret_return(ret, -1, "__req_focus_pos err.\n");
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+int discam_get_af_status(struct v4l2_subdev *sd, __u8 * status, __u16 * pos)
+{
+       struct i2c_client *client;
+       struct discam_device *dev;
+       int ret = 0;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       __check_dev_null_return(sd, -EINVAL);
+
+       dev = to_discam_device(sd);
+       client = v4l2_get_subdevdata(sd);
+
+       if (dev->status == DIS_STATUS_POWER_DOWN) {
+               __discam_warn("startup.\n");
+               ret = discam_startup(sd);
+               __check_ret_return(ret, -1, "startup err.\n");
+       }
+
+       /*
+        * need to wakeup sensor first ?
+        */
+       if (dev->status == DIS_STATUS_STANDBY) {
+               ret = discam_wakeup(sd);
+               __check_ret_return(ret, -1, "discam_wakeup err.\n");
+       }
+
+       ret = __get_af_status(client, status, pos);
+       __check_ret_return(ret, -1, "__get_af_status err.\n");
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+int discam_config_auto_focus(struct v4l2_subdev *sd, int internal)
+{
+       struct i2c_client *client;
+       struct discam_device *dev;
+       int ret = 0;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       __check_dev_null_return(sd, -EINVAL);
+
+       dev = to_discam_device(sd);
+       client = v4l2_get_subdevdata(sd);
+
+       if (dev->status == DIS_STATUS_POWER_DOWN) {
+               __discam_warn("startup.\n");
+               ret = discam_startup(sd);
+               __check_ret_return(ret, -1, "startup err.\n");
+       }
+
+       /*
+        * need to wakeup sensor first ?
+        */
+       if (dev->status == DIS_STATUS_STANDBY) {
+               ret = discam_wakeup(sd);
+               __check_ret_return(ret, -1, "discam_wakeup err.\n");
+       }
+
+       ret = __cfg_auto_focus(client, internal);
+       __check_ret_return(ret, -1, "__cfg_auto_focus err.\n");
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+int discam_config_focus_range(struct v4l2_subdev *sd, __u8 range)
+{
+       struct i2c_client *client;
+       struct discam_device *dev;
+       int ret = 0;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       __check_dev_null_return(sd, -EINVAL);
+
+       dev = to_discam_device(sd);
+       client = v4l2_get_subdevdata(sd);
+
+       if (dev->status == DIS_STATUS_POWER_DOWN) {
+               __discam_warn("startup.\n");
+               ret = discam_startup(sd);
+               __check_ret_return(ret, -1, "startup err.\n");
+       }
+
+       /*
+        * need to wakeup sensor first ?
+        */
+       if (dev->status == DIS_STATUS_STANDBY) {
+               ret = discam_wakeup(sd);
+               __check_ret_return(ret, -1, "discam_wakeup err.\n");
+       }
+
+       ret = __cfg_focus_range(client, range);
+       __check_ret_return(ret, -1, "__cfg_auto_focus err.\n");
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+int discam_req_auto_focus(struct v4l2_subdev *sd, __u32 sharpness)
+{
+       struct i2c_client *client;
+       struct discam_device *dev;
+       int ret = 0;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       __check_dev_null_return(sd, -EINVAL);
+
+       dev = to_discam_device(sd);
+       client = v4l2_get_subdevdata(sd);
+
+       /*
+        * need to wakeup sensor first ?
+        */
+       if (dev->status == DIS_STATUS_STANDBY) {
+               ret = discam_wakeup(sd);
+               __check_ret_return(ret, -1, "discam_wakeup err.\n");
+       }
+
+       ret = __req_auto_focus(client, sharpness);
+       __check_ret_return(ret, -1, "__req_auto_focus err.\n");
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+int discam_req_stop_auto_focus(struct v4l2_subdev *sd)
+{
+       struct i2c_client *client;
+       struct discam_device *dev;
+       int ret = 0;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       __check_dev_null_return(sd, -EINVAL);
+
+       dev = to_discam_device(sd);
+       client = v4l2_get_subdevdata(sd);
+
+       if (dev->status == DIS_STATUS_POWER_DOWN) {
+               __discam_warn("startup.\n");
+               ret = discam_startup(sd);
+               __check_ret_return(ret, -1, "startup err.\n");
+       }
+
+       /*
+        * need to wakeup sensor first ?
+        */
+       if (dev->status == DIS_STATUS_STANDBY) {
+               ret = discam_wakeup(sd);
+               __check_ret_return(ret, -1, "discam_wakeup err.\n");
+       }
+
+       ret = __req_stop_auto_focus(client);
+       __check_ret_return(ret, -1, "__req_stop_auto_focus err.\n");
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+/* *****************************************************************
+ * supported V4L2 Control IDs.
+ * *****************************************************************
+ */
+
+/*
+ * set/get exposure settings.
+ *
+ * currently the set operation will set value to viewfinder mode
+ * directly and snapshot should use vf parameter directly.
+ *
+ * FIXME: to add flag to choose if set exposure settings to
+ * viewfinder mode or snapshot mode (use manual setting).
+ */
+static int __discam_s_exposure(struct v4l2_subdev *sd, __u32 val)
+{
+       __u32 real;
+
+       __check_dev_null_return(sd, -EINVAL);
+
+       return discam_set_itg_time(sd, (__u16) val, &real);
+}
+
+static int __discam_g_exposure(struct v4l2_subdev *sd, __u32 * val)
+{
+       int ret;
+       __u32 itg_time;
+       __u16 iso;
+       __u8 aperture;
+
+       __check_dev_null_return(sd, -EINVAL);
+
+       ret = discam_get_exposure_setting(sd, &itg_time, &iso, &aperture);
+       __check_ret_return(ret, -1, "discam_get_exposure_setting err.\n");
+
+       (*val) = itg_time;
+
+       return 0;
+}
+
+static int __discam_s_iso(struct v4l2_subdev *sd, __u32 val)
+{
+       __u16 real;
+
+       __check_dev_null_return(sd, -EINVAL);
+
+       return discam_set_iso(sd, (__u16) val, &real);
+}
+
+static int __discam_g_iso(struct v4l2_subdev *sd, __u32 * val)
+{
+       int ret;
+       __u32 itg_time;
+       __u16 iso;
+       __u8 aperture;
+
+       __check_dev_null_return(sd, -EINVAL);
+
+       ret = discam_get_exposure_setting(sd, &itg_time, &iso, &aperture);
+       __check_ret_return(ret, -1, "discam_get_exposure_setting err.\n");
+
+       (*val) = iso;
+
+       return 0;
+}
+
+static int __discam_s_aperture(struct v4l2_subdev *sd, __u32 val)
+{
+       __check_dev_null_return(sd, -EINVAL);
+
+       return discam_set_aperture(sd, (__u8) val);
+}
+
+static int __discam_g_aperture(struct v4l2_subdev *sd, __u32 * val)
+{
+       int ret;
+       __u32 itg_time;
+       __u16 iso;
+       __u8 aperture;
+
+       __check_dev_null_return(sd, -EINVAL);
+
+       ret = discam_get_exposure_setting(sd, &itg_time, &iso, &aperture);
+       __check_ret_return(ret, -1, "discam_get_exposure_setting err.\n");
+
+       (*val) = aperture;
+
+       return 0;
+}
+
+static int __discam_s_flash(struct v4l2_subdev *sd, __u32 val)
+{
+       __u16 addr;
+       __u8 data;
+
+       __check_dev_null_return(sd, -EINVAL);
+
+       addr = STROBE_IO_CTRL;
+       discam_read_sensor_register(sd, addr, &data);
+       data |= (1 << 1); /* bit1: register control value */
+       discam_write_sensor_register(sd, addr, data);
+
+       addr = STROBE_OUTPUT_SEL;
+       discam_read_sensor_register(sd, addr, &data);
+       data |= (1 << 1); /* bit1: output */
+       discam_write_sensor_register(sd, addr, data);
+
+       addr = STROBE_OUTPUT_VAL;
+       discam_read_sensor_register(sd, addr, &data);
+       if (val)
+               data |= (1 << 1); /* bit1: output value to high */
+       else
+               data &= (~(1 << 1)); /* bit1: output value to low */
+       discam_write_sensor_register(sd, addr, data);
+
+       addr = STROBE_CTRL;
+       discam_read_sensor_register(sd, addr, &data);
+       data = 0xff;
+       discam_write_sensor_register(sd, addr, data);
+
+       return 0;
+}
+
+static int __discam_g_flash(struct v4l2_subdev *sd, __u32 * val)
+{
+       __check_dev_null_return(sd, -EINVAL);
+
+       return 0;
+}
+
+static int __discam_s_focus(struct v4l2_subdev *sd, __u32 val)
+{
+       __check_dev_null_return(sd, -EINVAL);
+
+       return discam_req_focus_pos(sd, (__u16) val);
+}
+
+static int __discam_g_focus(struct v4l2_subdev *sd, __u32 * val)
+{
+       int ret;
+       __u8 focus_status;
+       __u16 focus_pos;
+
+       __check_dev_null_return(sd, -EINVAL);
+
+       ret = discam_get_af_status(sd, &focus_status, &focus_pos);
+
+       __check_ret_return(ret, -1, "discam_get_af_status err.\n");
+
+       (*val) = focus_pos;
+
+       return 0;
+}
+
+static const struct __s_ctrl_id __DISCAM_CTRLS[] = {
+       __s_ctrl_id_entry_integer(V4L2_CID_EXPOSURE_ABSOLUTE,
+                                 "Absolute Exposure", 0, 0xffff, 1, 0, 0,
+                                 __discam_s_exposure,
+                                 __discam_g_exposure),
+       __s_ctrl_id_entry_integer(V4L2_CID_ISO_ABSOLUTE,
+                                 "Absolute ISO", 0, 0xffff, 1, 0, 0,
+                                 __discam_s_iso,
+                                 __discam_g_iso),
+       __s_ctrl_id_entry_integer(V4L2_CID_APERTURE_ABSOLUTE,
+                                 "Absolute Aperture", 0, 0xffff, 1, 0, 0,
+                                 __discam_s_aperture,
+                                 __discam_g_aperture),
+       __s_ctrl_id_entry_integer(V4L2_CID_FOCUS_ABSOLUTE,
+                                 "Absolute Focus", 0, 0xffff, 1, 0, 0,
+                                 __discam_s_focus,
+                                 __discam_g_focus),
+       __s_ctrl_id_entry_integer(V4L2_CID_FLASH_STROBE,
+                               "Absolute flash", 0, 0xffff, 1, 0, 0,
+                               __discam_s_flash,
+                               __discam_g_flash),
+};
+
+static const int __DISCAM_CTRL_NR =
+       sizeof(__DISCAM_CTRLS) / sizeof(__DISCAM_CTRLS[0]);
+
+static struct __s_ctrl_id *__find_ctrl_id(unsigned int id)
+{
+       int i;
+
+       for (i = 0; i < __DISCAM_CTRL_NR; i++) {
+               if (__DISCAM_CTRLS[i].qc.id == id)
+                       return (struct __s_ctrl_id *)&__DISCAM_CTRLS[i];
+       }
+
+       return NULL;
+}
+
+/* ************************************************************
+ * Core operations
+ * ***********************************************************
+ */
+int discam_g_chip_ident(struct v4l2_subdev *sd,
+                       struct v4l2_dbg_chip_ident *chip)
+{
+       struct discam_device *dev;
+       struct i2c_client *client;
+
+       client = v4l2_get_subdevdata(sd);
+       dev = to_discam_device(sd);
+
+       if (!chip)
+               return -EINVAL;
+
+       chip->ident = dev->sensor_id;
+       chip->revision = dev->sensor_revision;
+       chip->match.type = V4L2_CHIP_MATCH_I2C_DRIVER;
+       chip->match.addr = client->addr;
+       strlcpy(chip->match.name, client->name, strlen(client->name));
+
+       return 0;
+}
+
+int discam_log_status(struct v4l2_subdev *sd)
+{
+       struct discam_device *dev;
+       struct i2c_client *client;
+
+       client = v4l2_get_subdevdata(sd);
+       dev = to_discam_device(sd);
+
+       return 0;
+}
+
+int discam_s_config(struct v4l2_subdev *sd, int irq, void *platform_data)
+{
+       struct discam_device *dev;
+       struct i2c_client *client;
+
+       client = v4l2_get_subdevdata(sd);
+       dev = to_discam_device(sd);
+
+       /* FIXME: do nothing now ... */
+
+       return 0;
+}
+
+int discam_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+       struct discam_device *dev;
+       struct i2c_client *client;
+
+       client = v4l2_get_subdevdata(sd);
+       dev = to_discam_device(sd);
+
+       if (!qc)
+               return -EINVAL;
+
+       if (qc->id >= __DISCAM_CTRL_NR)
+               return -EINVAL;
+
+       (*qc) = __DISCAM_CTRLS[qc->id].qc;
+
+       return 0;
+}
+
+int discam_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct discam_device *dev;
+       struct i2c_client *client;
+       struct __s_ctrl_id *__s_ctrl;
+
+       client = v4l2_get_subdevdata(sd);
+       dev = to_discam_device(sd);
+
+       if (!ctrl)
+               return -EINVAL;
+
+       __s_ctrl = __find_ctrl_id(ctrl->id);
+       if (NULL == __s_ctrl)
+               return -EINVAL;
+
+       return __s_ctrl->s_ctrl(sd, ctrl->value);
+}
+
+int discam_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+       struct discam_device *dev;
+       struct i2c_client *client;
+       struct __s_ctrl_id *__s_ctrl;
+
+       client = v4l2_get_subdevdata(sd);
+       dev = to_discam_device(sd);
+
+       if (!ctrl)
+               return -EINVAL;
+
+       __s_ctrl = __find_ctrl_id(ctrl->id);
+       if (NULL == __s_ctrl)
+               return -EINVAL;
+
+       return __s_ctrl->g_ctrl(sd, &ctrl->value);
+}
+
+int discam_init(struct v4l2_subdev *sd, u32 val)
+{
+       struct discam_device *dev;
+       struct i2c_client *client;
+       int ret;
+       client = v4l2_get_subdevdata(sd);
+       dev = to_discam_device(sd);
+       if (val && !dev->init) {
+               dev->init = 1;
+               __discam_dbg(DBG_LEVEL_1,
+                       "request firmware from binary file...\n");
+               if (request_firmware(&g_this_camera->fw,
+                       g_this_camera->fw_file, &(client->dev)) != 0) {
+                       __discam_dbg(DBG_LEVEL_1, "fail to open firmware %s\n",
+                       g_this_camera->fw_file);
+                       return -EINVAL;
+               }
+               __discam_dbg(DBG_LEVEL_1, "done...\n");
+
+               ret = __startup(client);
+               if (ret) {
+                       __discam_dbg(DBG_LEVEL_1, "discam startup err.\n");
+                       return -EINVAL;
+               }
+
+               dev->status = DIS_STATUS_ACTIVE;
+
+               ret = discam_get_fw_version(sd,
+                       &dev->fw_version, &dev->fw_revision);
+
+               __check_ret_return(ret, -1, "discam_get_fw_version err.\n");
+
+               ret = discam_get_sensor_version(sd,
+               &dev->sensor_id, &dev->sensor_revision);
+               __check_ret_return(ret, -1, "discam_get_sensor_version err.\n");
+
+
+               __discam_dbg(DBG_LEVEL_1,
+                       "firmware version: 0x%x, revision: 0x%x\n",
+               dev->fw_version, dev->fw_revision);
+               __discam_dbg(DBG_LEVEL_1,
+                       "sensor id: 0x%x, revision: 0x%x\n",
+               dev->sensor_id, dev->sensor_revision);
+
+               __check_ret_return(ret, -1,
+                       "put camera module to standby mode.\n");
+               ret = discam_standby(sd);
+               __check_ret_return(ret, -1, "discam_standby err.\n");
+
+               if (!g_discam_start_vf && !g_discam_test)
+                       goto quit;
+
+               if (g_discam_test && !g_discam_start_vf)
+                       __discam_dbg(DBG_LEVEL_1,
+                               "running test cmd to test camera module...\n");
+
+               __check_ret_return(ret, -1, "wake up from standby.\n");
+
+               ret = discam_wakeup(sd);
+                       __check_ret_return(ret, -1, "discam_wakeup err.\n");
+
+               __discam_dbg(DBG_LEVEL_1,
+                       "start viewfinder with mode: 0x%x\n", g_discam_vf_mode);
+
+               ret = discam_start_viewfinder(sd, g_discam_vf_mode);
+
+               if (ret)
+                       __discam_dbg(DBG_LEVEL_1, "start viewfinder err...\n");
+               else
+                       __discam_dbg(DBG_LEVEL_1, "done...\n");
+
+               if (g_discam_start_vf)
+                       goto quit;
+
+               __discam_dbg(DBG_LEVEL_1, "stop viewfinder mode\n");
+               ret = discam_stop_viewfinder(sd);
+
+               if (ret)
+                       __discam_dbg(DBG_LEVEL_1, "stop viewfinder err...\n");
+               else
+                       __discam_dbg(DBG_LEVEL_1, "done...\n");
+
+quit:
+               __set_mipi_lane(client, dev->num_of_lane);
+       }
+       return 0;
+}
+
+/*
+ * set power state of the sensor.
+ *
+ * power:
+ *     0:      power down
+ *     1:      startup
+ */
+int discam_s_power(struct v4l2_subdev *sd, int power)
+{
+       struct discam_device *dev;
+       struct i2c_client *client;
+       int ret;
+
+       client = v4l2_get_subdevdata(sd);
+       dev = to_discam_device(sd);
+
+       switch (power) {
+       case 0:
+               ret = discam_power_down(sd);
+               __check_ret_return(ret, -EINVAL, "discam_power_down err.\n");
+               break;
+       case 1:
+               ret = discam_startup(sd);
+               __check_ret_return(ret, -EINVAL, "discam_startup err.\n");
+               break;
+       default:
+               __discam_err("unsupported power state: %d, "
+                            "do nothing.\n", power);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+int discam_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+       struct discam_device *dev;
+       struct i2c_client *client;
+       int ret;
+
+       client = v4l2_get_subdevdata(sd);
+       dev = to_discam_device(sd);
+
+       return 0;
+}
+
+int discam_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+       struct discam_device *dev;
+       struct i2c_client *client;
+       int ret;
+
+       client = v4l2_get_subdevdata(sd);
+       dev = to_discam_device(sd);
+
+       return 0;
+}
+#endif
+
+/*
+ * video operations
+ */
+
+/*
+ * how to deside
+ */
+int discam_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct discam_device *dev;
+       struct i2c_client *client;
+       int ret;
+
+       client = v4l2_get_subdevdata(sd);
+       dev = to_discam_device(sd);
+
+       /*
+        * if in viewfinder mode, start/stop viewfinder here.
+        *
+        * if in snapshot mode, do nothing in stream on/off,
+        * image flow is controlled in dqbuf/qbuf
+        */
+       if (dev->mode == DIS_VIEWFINDER_MODE) {
+               if (enable) {
+                       ret = discam_start_viewfinder(sd,
+                               g_this_camera->fmts[dev->fmt_idx].modeval);
+                       __check_ret_return(ret, -1,
+                                          "discam_start_viewfinder err.\n");
+               } else {
+                       ret = discam_stop_viewfinder(sd);
+                       __check_ret_return(ret, -1,
+                                          "discam_stop_viewfinder err.\n");
+               }
+       }
+
+       return 0;
+}
+
+int discam_enum_fmt(struct v4l2_subdev *sd, struct v4l2_fmtdesc *fmtdesc)
+{
+       struct discam_device *dev;
+       struct i2c_client *client;
+
+       client = v4l2_get_subdevdata(sd);
+       dev = to_discam_device(sd);
+
+       if (!fmtdesc)
+               return -EINVAL;
+
+       if (fmtdesc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               __discam_err("unsupported buffer type.\n");
+               return -EINVAL;
+       }
+
+       if (fmtdesc->index >= g_this_camera->fmt_nr) {
+               __discam_err("index out of bound.\n");
+               return -EINVAL;
+       }
+
+       fmtdesc->pixelformat = g_this_camera->fmts[fmtdesc->index]
+           .s_fmt.v4l2_fmt.fmt.pix.pixelformat;
+
+       return 0;
+}
+
+/*
+ * select the most nearest format according to resolution and format.
+ * the g_this_camera->fmts are listed in a decresing order.
+ *
+ * FIXME: only use viewfinder mode now. need to add code to handle
+ * snapshot mode.
+ */
+static __u32 __distance(__u32 snr_width, __u32 snr_height,
+                       __u32 width, __u32 height)
+{
+       return (snr_width - width) + (snr_height - height);
+}
+
+static int __select_nearest_fmt(__u32 width, __u32 height, __u32 pixelformat)
+{
+       int i;
+       int check_fmt;
+       __u32 w, h, p;
+       __u32 dist, min_dist;
+       int fmt_idx;
+
+       check_fmt = 1;
+       fmt_idx = g_this_camera->fmt_nr;
+       min_dist = 0xffffffff;
+retry:
+       for (i = 0; i < g_this_camera->fmt_nr; i++) {
+               /*
+                * FIXME:
+                *
+                * only use viewfinder mode now.
+                */
+               if (g_this_camera->fmts[i].mode == DIS_SNAPSHOT_MODE)
+                       continue;
+
+               w = g_this_camera->fmts[i].s_fmt.v4l2_fmt.fmt.pix.width;
+               h = g_this_camera->fmts[i].s_fmt.v4l2_fmt.fmt.pix.height;
+               p = g_this_camera->fmts[i].s_fmt.v4l2_fmt.fmt.pix.pixelformat;
+
+               if (check_fmt && (p != pixelformat))
+                       continue;
+
+               if (w < width || h < height)
+                       continue;
+
+               dist = __distance(w, h, width, height);
+               if (min_dist > dist) {
+                       min_dist = dist;
+                       fmt_idx = i;
+               }
+       }
+
+       if (fmt_idx == g_this_camera->fmt_nr) {
+               if (check_fmt) {
+                       check_fmt = 0;
+                       goto retry;
+               } else {
+                       fmt_idx = 0;
+                       __discam_err("camera does not support any resolution "
+                                    "that is larger than %d * %d, "
+                                    "set to default resolution.\n",
+                                    width, height);
+               }
+       }
+
+       w = g_this_camera->fmts[fmt_idx].s_fmt.v4l2_fmt.fmt.pix.width;
+       h = g_this_camera->fmts[fmt_idx].s_fmt.v4l2_fmt.fmt.pix.height;
+       p = g_this_camera->fmts[fmt_idx].s_fmt.v4l2_fmt.fmt.pix.pixelformat;
+
+       __discam_dbg(DBG_LEVEL_2, "choose resolution: %d * %d.\n", w, h);
+
+       return fmt_idx;
+}
+
+/*
+ * FIXME: not consider viewfinder mode or snapshot mode now. need to
+ * add code to handle this.
+ */
+int discam_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+{
+       struct discam_device *dev;
+       struct i2c_client *client;
+       int idx;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       client = v4l2_get_subdevdata(sd);
+       dev = to_discam_device(sd);
+
+       if (!fmt)
+               return -EINVAL;
+
+       if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               __discam_err("unsupported buffer type.\n");
+               return -EINVAL;
+       }
+
+       /*
+        * only return a suitable format, not really setup
+        * format here
+        */
+       idx = __select_nearest_fmt(fmt->fmt.pix.width,
+                                  fmt->fmt.pix.height,
+                                  fmt->fmt.pix.pixelformat);
+
+       fmt->fmt.pix.width =
+           g_this_camera->fmts[idx].s_fmt.v4l2_fmt.fmt.pix.width;
+       fmt->fmt.pix.height =
+           g_this_camera->fmts[idx].s_fmt.v4l2_fmt.fmt.pix.height;
+       fmt->fmt.pix.pixelformat =
+           g_this_camera->fmts[idx].s_fmt.v4l2_fmt.fmt.pix.pixelformat;
+
+       __discam_dbg(DBG_LEVEL_2, "find most suitable resolution: idx = %d"
+                    "width = %d, height = %d\n", idx,
+                    fmt->fmt.pix.width, fmt->fmt.pix.height);
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+int discam_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+{
+       struct discam_device *dev;
+       struct i2c_client *client;
+
+       client = v4l2_get_subdevdata(sd);
+       dev = to_discam_device(sd);
+
+       if (!fmt)
+               return -EINVAL;
+
+       if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               __discam_err("unsupported buffer type.\n");
+               return -EINVAL;
+       }
+
+       fmt->fmt.pix.width = g_this_camera->fmts[dev->fmt_idx]
+           .s_fmt.v4l2_fmt.fmt.pix.width;
+       fmt->fmt.pix.height = g_this_camera->fmts[dev->fmt_idx]
+           .s_fmt.v4l2_fmt.fmt.pix.height;
+       fmt->fmt.pix.pixelformat = g_this_camera->fmts[dev->fmt_idx]
+           .s_fmt.v4l2_fmt.fmt.pix.pixelformat;
+
+       return 0;
+}
+
+/*
+ * FIXME: not consider viewfinder mode or snapshot mode now. need to
+ * add code to handle this.
+ */
+int discam_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+{
+       struct discam_device *dev;
+       struct i2c_client *client;
+       int ret;
+
+       __discam_dbg(DBG_LEVEL_2, "enter...\n");
+
+       client = v4l2_get_subdevdata(sd);
+       dev = to_discam_device(sd);
+
+       ret = discam_try_fmt(sd, fmt);
+       __check_ret_return(ret, -1, "discam_try_fmt err.\n");
+
+       /*
+        * target format will not be set in discam_try_fmt,
+        * set it here
+        */
+       dev->fmt_idx = __get_vf_fmt_idx(fmt->fmt.pix.width,
+                                       fmt->fmt.pix.height);
+
+       __discam_dbg(DBG_LEVEL_2,
+               "set to format: idx = %d, width = %d, height = %d.\n",
+               dev->fmt_idx, fmt->fmt.pix.width, fmt->fmt.pix.height);
+
+       dev->mode = g_this_camera->fmts[dev->fmt_idx].mode;
+
+       __discam_dbg(DBG_LEVEL_2, "leave...\n");
+
+       return 0;
+}
+
+int discam_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *param)
+{
+       struct discam_device *dev;
+       struct i2c_client *client;
+
+       client = v4l2_get_subdevdata(sd);
+       dev = to_discam_device(sd);
+
+       if (!param)
+               return -EINVAL;
+
+       if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               __discam_err("unsupported buffer type.\n");
+               return -EINVAL;
+       }
+
+       /* support nothing */
+       memset(&param->parm, 0, sizeof(struct v4l2_captureparm));
+
+       return 0;
+}
+
+int discam_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *param)
+{
+       struct discam_device *dev;
+       struct i2c_client *client;
+
+       client = v4l2_get_subdevdata(sd);
+       dev = to_discam_device(sd);
+
+       if (!param)
+               return -EINVAL;
+
+       if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               __discam_err("unsupported buffer type.\n");
+               return -EINVAL;
+       }
+
+       /* we dont support frame rate control in driver. */
+       if (param->parm.capture.capability | V4L2_CAP_TIMEPERFRAME) {
+               __discam_err("time per frame is not supported.\n");
+               return -EINVAL;
+       }
+
+       /* FIXME: add code to handle capturemode field? */
+
+       return 0;
+}
+
+static int __find_format(__u32 index, __u32 pixelformat)
+{
+       int i;
+       __u32 idx, fmt;
+
+       idx = 0;
+       for (i = 0; i < g_this_camera->fmt_nr; i++) {
+               fmt = g_this_camera->fmts[i].s_fmt.v4l2_fmt.fmt.pix.pixelformat;
+               if (fmt != pixelformat)
+                       continue;
+               if (idx == index)
+                       return i;
+               idx++;
+       }
+
+       return -1;
+}
+
+int discam_enum_framesizes(struct v4l2_subdev *sd,
+                          struct v4l2_frmsizeenum *fsize)
+{
+       struct discam_device *dev;
+       struct i2c_client *client;
+       int idx;
+
+       client = v4l2_get_subdevdata(sd);
+       dev = to_discam_device(sd);
+
+       if (!fsize)
+               return -EINVAL;
+
+       idx = __find_format(fsize->index, fsize->pixel_format);
+       if (idx == -1) {
+               __discam_err("index out of range or "
+                            "pixelformat not supported.\n");
+               return -EINVAL;
+       }
+
+       fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+       fsize->discrete.width =
+           g_this_camera->fmts[idx].s_fmt.v4l2_fmt.fmt.pix.width;
+       fsize->discrete.height =
+           g_this_camera->fmts[idx].s_fmt.v4l2_fmt.fmt.pix.height;
+
+       return 0;
+}
+
+int discam_enum_frameintervals(struct v4l2_subdev *sd,
+                              struct v4l2_frmivalenum *fival)
+{
+       struct discam_device *dev;
+       struct i2c_client *client;
+
+       client = v4l2_get_subdevdata(sd);
+       dev = to_discam_device(sd);
+
+       if (!fival)
+               return -EINVAL;
+
+       __discam_err("frame rate control is not supported.\n");
+
+       return -EINVAL;
+}
+
+/*
+ * FIXME: where to setup if using viewfinder mode or snapshot mode???
+ * sensor driver decide in s_fmt, or caller pass the mode to sensor
+ * driver???
+ */
+static const struct v4l2_subdev_video_ops discam_video_ops = {
+       .s_stream = discam_s_stream,
+       .enum_fmt = discam_enum_fmt,
+       .try_fmt = discam_try_fmt,
+       .g_fmt = discam_g_fmt,
+       .s_fmt = discam_s_fmt,
+       .g_parm = discam_g_parm,
+       .s_parm = discam_s_parm,
+       .enum_framesizes = discam_enum_framesizes,
+       .enum_frameintervals = discam_enum_frameintervals,
+};
+
+static const struct v4l2_subdev_core_ops discam_core_ops = {
+       .g_chip_ident = discam_g_chip_ident,
+       .log_status = discam_log_status,
+       .s_config = discam_s_config,
+       .queryctrl = discam_queryctrl,
+       .g_ctrl = discam_g_ctrl,
+       .s_ctrl = discam_s_ctrl,
+       .s_power = discam_s_power,
+       .init = discam_init,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .g_register = discam_g_register,
+       .s_register = discam_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_ops discam_ops = {
+       .core = &discam_core_ops,
+       .video = &discam_video_ops,
+};
+
+int discam_detect(struct i2c_client *client)
+{
+       struct i2c_adapter *adapter = client->adapter;
+       int adapter_id = i2c_adapter_id(adapter);
+       int ret;
+
+       __discam_dbg(DBG_LEVEL_1, "discam_detect...\n");
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
+               return -ENODEV;
+
+       if (adapter_id != 4) {
+               __discam_dbg(DBG_LEVEL_1, "adapter_id is not correct.\n");
+               return -ENODEV;
+       }
+
+       ret = gpio_direction_output(GP_CAMERA_0_RESET, 0);
+       __check_ret_return(ret, -1, "gpio_direction_output err.\n");
+       ret = gpio_direction_output(GP_CAMERA_0_RESET, 1);
+       __check_ret_return(ret, -1, "gpio_direction_output err.\n");
+
+       gpio_free(GP_CAMERA_0_RESET);
+
+       /* ret = __startup(client); */
+       __discam_dbg(DBG_LEVEL_1, "set internal SRAM device ID...\n");
+       ret = __discam_write(client, 0x19, 0x67);
+       __check_ret_return(ret, -1, "set internal SRAM device ID err.\n");
+       __discam_dbg(DBG_LEVEL_1, "set internal SRAM device ID... done.\n");
+
+       if (ret) {
+               __discam_dbg(DBG_LEVEL_1, "discam startup err.\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static void __init_discam_dev(struct discam_device *dev,
+                             struct mfld_ci_mipi_camera *cam)
+{
+       if (!dev || !cam)
+               return;
+
+       cam->port = MIPI_PORT_LANE_4;
+       cam->num_of_lane = 4;
+       cam->input_format = INPUT_FORMAT_RAW_10;
+       cam->raw_bayer_order = BAYER_ORDER_BGGR;
+
+       dev->num_of_lane = 4;
+       dev->mode = 0;          /* viewfinder or snapshot */
+       dev->fmt_idx = 0;
+       dev->status = 0;
+       dev->fw_version = 0;
+       dev->fw_revision = 0;
+       dev->sensor_id = 0;
+       dev->sensor_revision = 0;
+       dev->cur_vf_mode = 0xff;        /* invalid mode */
+       dev->init = 0;
+}
+
+int discam_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+       struct mfld_ci_mipi_camera *dis_cam;
+       struct discam_device *dev;
+       struct v4l2_subdev *sd;
+       int ret;
+
+       __discam_dbg(DBG_LEVEL_1, "discam_probe...\n");
+
+       ret = discam_detect(client);
+       if (ret) {
+               __discam_err("discam_detect err.\n");
+               return ret;
+       }
+
+       dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev) {
+               __discam_err("out of memory\n");
+               return -ENOMEM;
+       }
+
+       dis_cam = kmalloc(sizeof(*dis_cam), GFP_KERNEL);
+       if (!dis_cam) {
+               __discam_err("out of memory\n");
+               kfree(dev);
+               return -ENOMEM;
+       }
+
+       __init_discam_dev(dev, dis_cam);
+
+       v4l2_i2c_subdev_init(&(dev->sd), client, &discam_ops);
+
+       sd = &dev->sd;
+       v4l2_set_subdevdata(sd, (void *)dis_cam);
+
+       /* already called __startup in discam_detect */
+       dev->status = DIS_STATUS_POWER_DOWN;
+
+       __discam_dbg(DBG_LEVEL_1, "discam_probe... done ...\n");
+
+       return 0;
+}
+
+int discam_remove(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+       struct discam_device *dev = to_discam_device(sd);
+       int ret;
+
+       ret = discam_power_down(sd);
+       __check_ret(ret, "discam_power_down err.\n");
+
+       kfree(dev);
+
+       if (g_this_camera->fw)
+               release_firmware(g_this_camera->fw);
+
+       return ret;
+}
+
+int discam_suspend(struct i2c_client *client, pm_message_t state)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+       /* hardware power down the module */
+       return discam_power_down(sd);
+}
+
+int discam_resume(struct i2c_client *client)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+       /* startup the module, but not outputing image */
+       return discam_startup(sd);
+}
+
+static const struct i2c_device_id g_discam_id[] = {
+       {DISCAM_NAME, 0},
+       {},
+};
+
+MODULE_DEVICE_TABLE(i2c, g_discam_id);
+
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+       .name = DISCAM_NAME,
+       .probe = discam_probe,
+       .remove = discam_remove,
+       .suspend = discam_suspend,
+       .resume = discam_resume,
+       .id_table = g_discam_id,
+};
+
+MODULE_AUTHOR("Kai Huang <kai.huang at intel.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/mfld_ci/discam/discam.h b/drivers/media/video/mfld_ci/discam/discam.h
new file mode 100644
index 0000000..83f537d
--- /dev/null
+++ b/drivers/media/video/mfld_ci/discam/discam.h
@@ -0,0 +1,342 @@
+/*
+ * Support for Medfield Penwell Camera Imaging ISP subsystem.
+ *
+ * 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.
+ *
+ */
+
+/*
+ * common macro/structure/function definition for DIS sensor.
+ *
+ * Kai Huang, kai.huang at intel.com
+ *
+ * History:
+ *     V0.1    Written according to DIS-AN10-1103 (CommandIF-MIPI) v3.3
+ */
+
+#ifndef        __DISCAM_H__
+#define        __DISCAM_H__
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include <linux/spinlock.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+
+#include "sensor_com.h"
+#include "cam_gpio.h"
+
+/* command register address */
+#define        DIS_PROC_CMD    0xc5
+#define        DIS_PROC_REG0   0xc1
+#define        DIS_PROC_REG1   0xc2
+#define        DIS_PROC_REG2   0xc3
+#define        DIS_PROC_REG3   0xc4
+
+/* command status */
+#define        DIS_CMD_STATUS_BUSY     0xfe
+#define        DIS_CMD_STATUS_IDLE     0xff
+
+/* command return value */
+#define        DIS_CMD_OK                              0x00
+#define        DIS_CMD_WRONG_PARAMETER                 0x01
+#define        DIS_CMD_NOT_IMPLEMENTED                 0x04
+#define        DIS_CMD_MOTOR_INIT_NOT_COMPLETED        0x12
+#define        DIS_CMD_INTERRUPT_CHANGE_ILLEGAL        0x13
+
+/* command list */
+#define        DIS_CMD_REQ_INIT                0x00
+#define        DIS_CMD_REQ_MOTOR_INIT          0x17
+#define        DIS_CMD_REQ_POWER_CTRL          0x01
+#define        DIS_CMD_GET_VERSION             0x02 /* get command fw version */
+#define        DIS_CMD_W_SENSOR_REG            0x09
+#define        DIS_CMD_R_SENSOR_REG            0x0a
+#define        DIS_CMD_W_REG                   0x0b
+#define        DIS_CMD_R_REG                   0x0c
+#define        DIS_CMD_CFG_LCT                 0x1d /* config Lens Correction Table */
+#define        DIS_CMD_REQ_LCT                 0x15 /* request Lens Correction Table */
+#define        DIS_CMD_SET_SENSOR_BL           0x2f /* set sensor Black Level */
+#define        DIS_CMD_GET_SENSOR_BL           0x2e /* get sensor Black Level */
+#define        DIS_CMD_REQ_ITG_TIME            0x21 /* request ... time */
+#define        DIS_CMD_REQ_ISO_SPEED           0x22
+#define        DIS_CMD_SET_APERTURE_POS        0x47
+#define        DIS_CMD_GET_APERTURE_POS        0x46
+#define        DIS_CMD_REQ_SHUTTER_USAGE       0x4f
+#define        DIS_CMD_CFG_SNAPSHOT_PARAM      0x28
+#define        DIS_CMD_GET_EXPOSURE_SETTING    0x29
+#define        DIS_CMD_REQ_VIEWFINDER          0x38
+#define        DIS_CMD_REQ_SNAPSHOT            0x3A
+#define        DIS_CMD_CFG_AUTO_FOCUS          0x11
+#define        DIS_CMD_REQ_AUTO_FOCUS          0x1c
+#define        DIS_CMD_REQ_STOP_AUTO_FOCUS     0x16
+#define        DIS_CMD_REQ_FOCUS_POS           0x18
+#define        DIS_CMD_GET_AFSTATUS            0x1e
+
+/* sensor mode */
+#define        DIS_VIEWFINDER_MODE             0
+#define        DIS_SNAPSHOT_MODE               1
+/*
+ * resolution mode
+ */
+#define        DIS_VIEWFINDER_MODE_4416_3312   0x18
+#define        DIS_VIEWFINDER_MODE_2112_1188   0x17
+#define        DIS_VIEWFINDER_MODE_1408_792    0x16
+#define        DIS_VIEWFINDER_MODE_1104_828    0x15
+#define        DIS_VIEWFINDER_MODE_1080P       0x0a
+#define        DIS_VIEWFINDER_MODE_720P        0x09
+#define        DIS_VIEWFINDER_MODE_VGA_CENTER  0x05
+#define        DIS_VIEWFINDER_MODE_1296_792    0x04
+#define        DIS_VIEWFINDER_MODE_2592_1944   0x03
+#define        DIS_VIEWFINDER_MODE_VGA_30FPS   0x00
+
+#define        DIS_VIEWFINDER_STOP             0x80
+
+#define        DIS_SNAPSHOT_MODE_4416_3312     0x07
+#define        DIS_SNAPSHOT_MODE_1080P         0x05
+#define        DIS_SNAPSHOT_MODE_1280_972      0x01
+#define        DIS_SNAPSHOT_MODE_2592_1944     0x00
+
+/*
+ * strobe relate register
+ */
+#define STROBE_IO_CTRL         0x3008
+#define STROBE_OUTPUT_SEL      0x300E
+#define STROBE_OUTPUT_VAL      0x3001
+#define STROBE_CTRL            0x3B00
+
+/*
+ * DIS sensor status
+ */
+#define        DIS_STATUS_POWER_DOWN   0x0
+#define        DIS_STATUS_STANDBY      0x2
+#define        DIS_STATUS_ACTIVE       0x03 /* meaning ready to output image */
+#define        DIS_STATUS_VIEWFINDER   0x4
+
+#define        V4L2_PIX_FMT_SBGGR12    v4l2_fourcc('B', 'Y', 'R', '1')
+
+/* command structure */
+struct dis_cmd {
+       __u8 proc_cmd;
+       __u8 proc_reg0;
+       __u8 proc_reg1;
+       __u8 proc_reg2;
+       __u8 proc_reg3;
+       __u8 cmd_status;
+       __u8 ret_reg0;
+       __u8 ret_reg1;
+       __u8 ret_reg2;
+       __u8 ret_reg3;
+};
+
+static inline void dis_cmd_clear(struct dis_cmd *cmd)
+{
+       memset(cmd, 0, sizeof(*cmd));
+}
+
+/*
+ *
+ */
+struct __dis_output_format {
+       struct __s_output_format s_fmt;
+       int mode;       /* viewfinder or snapshot */
+       __u8 modeval;   /* mode value */
+};
+
+#define        __dis_vf_output_format_entry(_width, _height, \
+               _pixelformat, _fps, _modeval) \
+       {\
+               .s_fmt = __s_output_format_entry(_width, _height,\
+                       _pixelformat, 0, V4L2_COLORSPACE_SRGB, _fps),\
+               .mode = DIS_VIEWFINDER_MODE,\
+               .modeval = (_modeval),\
+       }
+
+#define        __dis_ss_output_format_entry(_width, _height, \
+               _pixelformat, _fps, _modeval) \
+       {\
+               .s_fmt = __s_output_format_entry(_width, _height,\
+                       _pixelformat, 0, V4L2_COLORSPACE_SRGB, _fps),\
+               .mode = DIS_SNAPSHOT_MODE,\
+               .modeval = (_modeval),\
+       }
+
+/*
+ * discam device structure.
+ */
+struct discam_device {
+       struct v4l2_subdev sd;
+       /*
+        * discam specific member
+        */
+       int mode;               /* viewfinder or snapshot */
+       int fmt_idx;
+       __u8 num_of_lane;
+
+       int status;
+       int init;
+
+       __u8 fw_version;
+       __u16 fw_revision;
+       __u16 sensor_id;
+       __u8 sensor_revision;
+
+       /* */
+       __u8 cur_vf_mode;
+};
+
+#define        to_discam_device(p_sd)  \
+       container_of(p_sd, struct discam_device, sd)
+
+struct discam_driver {
+       char *name;
+       unsigned int addr;
+
+       struct __dis_output_format *fmts;
+       int fmt_nr;
+
+       __u8 default_vf_mode;
+       __u8 default_ss_mode;
+       char *fw_file;
+       const struct firmware *fw;
+};
+
+enum ENUM_DBG_LEVEL {
+       DBG_LEVEL_1 = 1,
+       DBG_LEVEL_2 = 2
+};
+/*
+ * debug macro definition
+ */
+#define        __discam_printk(level, fmt, arg ...) \
+       do {\
+               printk(level "%s: " fmt, DISCAM_NAME, ## arg); \
+               udelay(100); \
+       } while (0)
+
+#define        __discam_printk_detail(level, fmt, arg ...)     \
+       do {\
+               printk(level "%s: %s: %d: " fmt, DISCAM_NAME, \
+                       __func__, __LINE__, ## arg); \
+               udelay(100); \
+       } while (0)
+
+#define        __discam_info(fmt, arg ...)     \
+       __discam_printk(KERN_INFO, fmt, ## arg)
+
+#define        __discam_warn(fmt, arg ...)     \
+       __discam_printk(KERN_WARNING, fmt, ## arg)
+
+#define        __discam_err(fmt, arg ...)              \
+       __discam_printk_detail(KERN_ERR, fmt, ## arg)
+
+#define        __discam_dbg(level, fmt, arg ...)       \
+       do {\
+               if ((g_discam_dbg) >= (level)) \
+                       __discam_printk_detail(KERN_DEBUG, \
+                                       fmt, ## arg); \
+       } while (0)
+
+/*
+ * check command return value
+ */
+static const struct __macro_string g_dis_cmd_string[] = {
+       __macro_string_entry(DIS_CMD_REQ_INIT),
+       __macro_string_entry(DIS_CMD_REQ_INIT),
+       __macro_string_entry(DIS_CMD_REQ_MOTOR_INIT),
+       __macro_string_entry(DIS_CMD_REQ_POWER_CTRL),
+       __macro_string_entry(DIS_CMD_GET_VERSION),
+       __macro_string_entry(DIS_CMD_W_SENSOR_REG),
+       __macro_string_entry(DIS_CMD_R_SENSOR_REG),
+       __macro_string_entry(DIS_CMD_W_REG),
+       __macro_string_entry(DIS_CMD_R_REG),
+       __macro_string_entry(DIS_CMD_CFG_LCT),
+       __macro_string_entry(DIS_CMD_REQ_LCT),
+       __macro_string_entry(DIS_CMD_SET_SENSOR_BL),
+       __macro_string_entry(DIS_CMD_GET_SENSOR_BL),
+       __macro_string_entry(DIS_CMD_REQ_ITG_TIME),
+       __macro_string_entry(DIS_CMD_REQ_ISO_SPEED),
+       __macro_string_entry(DIS_CMD_SET_APERTURE_POS),
+       __macro_string_entry(DIS_CMD_GET_APERTURE_POS),
+       __macro_string_entry(DIS_CMD_REQ_SHUTTER_USAGE),
+       __macro_string_entry(DIS_CMD_CFG_SNAPSHOT_PARAM),
+       __macro_string_entry(DIS_CMD_GET_EXPOSURE_SETTING),
+       __macro_string_entry(DIS_CMD_REQ_VIEWFINDER),
+       __macro_string_entry(DIS_CMD_REQ_SNAPSHOT),
+       __macro_string_entry(DIS_CMD_CFG_AUTO_FOCUS),
+       __macro_string_entry(DIS_CMD_REQ_AUTO_FOCUS),
+       __macro_string_entry(DIS_CMD_REQ_STOP_AUTO_FOCUS),
+       __macro_string_entry(DIS_CMD_REQ_FOCUS_POS),
+       __macro_string_entry(DIS_CMD_GET_AFSTATUS),
+};
+
+static const int g_dis_cmd_size =
+       sizeof(g_dis_cmd_string) / sizeof(g_dis_cmd_string[0]);
+
+static const struct __macro_string g_dis_cmd_retval_string[] = {
+       __macro_string_entry(DIS_CMD_OK),
+       __macro_string_entry(DIS_CMD_WRONG_PARAMETER),
+       __macro_string_entry(DIS_CMD_NOT_IMPLEMENTED),
+       __macro_string_entry(DIS_CMD_MOTOR_INIT_NOT_COMPLETED),
+       __macro_string_entry(DIS_CMD_INTERRUPT_CHANGE_ILLEGAL),
+};
+
+static const int g_dis_cmd_retval_size = sizeof(g_dis_cmd_retval_string)
+       / sizeof(g_dis_cmd_retval_string[0]);
+
+#define        __dump_dis_cmd(cmd) \
+       do { \
+               __discam_err("CMD: %s. "\
+                       "Params: reg0 0x%x, reg1 0x%x, "\
+                               "reg2 0x%x, reg3 0x%x\n"\
+                       "\tReturn: reg0 0x%x, reg1 0x%x, "\
+                               "reg2 0x%x, reg3 0x%x\n",\
+                       __macro_to_string(\
+                               g_dis_cmd_string,\
+                               g_dis_cmd_size, \
+                               (cmd).proc_cmd), \
+                       (cmd).proc_reg0, \
+                       (cmd).proc_reg1, \
+                       (cmd).proc_reg2, \
+                       (cmd).proc_reg3, \
+                       (cmd). ret_reg0, \
+                       (cmd).ret_reg1, \
+                       (cmd).ret_reg2,\
+                       (cmd).ret_reg3); \
+       } while (0)
+
+#define        __discam_check_cmd_retval_return(cmd) \
+       do {\
+               if ((cmd).ret_reg0 != DIS_CMD_OK) { \
+                       __discam_err("CMD %s err, return %s.\n", \
+                               __macro_to_string(\
+                                       g_dis_cmd_string, \
+                                       g_dis_cmd_size, \
+                                       (cmd).proc_cmd), \
+                               __macro_to_string(\
+                                       g_dis_cmd_retval_string,\
+                                       g_dis_cmd_retval_size, \
+                                       (cmd).ret_reg0));\
+                       __dump_dis_cmd(cmd);\
+                       return -1;\
+               } \
+       } while (0)
+
+#endif
diff --git a/drivers/media/video/mfld_ci/discam/discam_cmd.h b/drivers/media/video/mfld_ci/discam/discam_cmd.h
new file mode 100644
index 0000000..68d590b
--- /dev/null
+++ b/drivers/media/video/mfld_ci/discam/discam_cmd.h
@@ -0,0 +1,403 @@
+/*
+ * Support for Medfield Penwell Camera Imaging ISP subsystem.
+ *
+ * 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.
+ *
+ */
+
+#ifndef        __DISCAM_CMD_H__
+#define        __DISCAM_CMD_H__
+
+#include "discam.h"
+
+/******************************************************************
+ * general operations for DIS camera
+ ******************************************************************
+ */
+
+/*
+ * get viewfinder mode or snapshot mode according to the resolution.
+ */
+__u8 discam_get_vf_mode(unsigned int width, unsigned int height);
+
+__u8 discam_get_ss_mode(unsigned int width, unsigned int height);
+
+/*
+ * start up and initialization. called before any command operation.
+ */
+int discam_startup(struct v4l2_subdev *sd);
+
+/*
+ * This command must be executed before turning off the clock and
+ * VDD to the module. It halts the processor and powers off the
+ * module.
+ *
+ * In this mode, register settings will be lost and discam_startup
+ * needs to be called again to make sensor work correctly.
+ *
+ * CMD:        DIS_CMD_REQ_POWER_CTRL  (Cmd_requestPowerControl)
+ * ARG:        PROC_REG0       0x01    -- power down
+ *     PROC_REG1       0x01    -- power down
+ */
+int discam_power_down(struct v4l2_subdev *sd);
+
+/*
+ * This command puts the module into low power stand-by mode.
+ * The motor will be powered off, image flow will be stopped,
+ * process put in halt mode and supply to various parts turned off.
+ *
+ * In this mode, the register settings will be maintained so that
+ * we dont have to store the settings manually.
+ *
+ * This command should not be executed twice in a row, in this case
+ * DIS_CMD_INTERRUPT_CHANGE_ILLEGAL is returned.
+ *
+ * CMD: DIS_CMD_REQ_POWER_CTRL
+ * ARG:        PROC_REG0       0x03    -- standby
+ *     PROC_REG1       0x00    -- standby
+ */
+int discam_standby(struct v4l2_subdev *sd);
+
+/*
+ * This command returns the system from stand-by mode. The image
+ * flow will not be restarted here.
+ *
+ * This command should not be executed if the system is not sent in
+ * the stand-by mode. In this case DIS_CMD_INTERRUPT_CHANGE_ILLEGAL
+ * returned.
+ *
+ * CMD:        DIS_CMD_REQ_POWER_CTRL
+ * ARG:        PROC_REG0       0x03    -- standby
+ *     PROC_REG1       0x01    -- restart
+ */
+int discam_wakeup(struct v4l2_subdev *sd);
+
+/*
+ * This command returns the firmware device id and revision number.
+ *
+ * can be called when system in standby ?
+ *
+ * CMD: DIS_CMD_GET_VERSION    (Cmd_getVersion)
+ * ARG:        PROC_REG0       0x00    -- firmware version
+ * RET:        PROC_REG1       firmware version
+ *     PROC_REG2       firmware revision (MSB)
+ *     PROC_REG3       firmware revision (LSB)
+ */
+int discam_get_fw_version(struct v4l2_subdev *sd,
+                         __u8 *version, __u16 *revision);
+
+/*
+ * This command returns the sensor id and revision number.
+ *
+ * can be called when system in standby ?
+ *
+ * CMD: DIS_CMD_GET_VERSION    (Cmd_getVersion)
+ * ARG:        PROC_REG0       0x01    -- sensor id
+ * RET:        PROC_REG1       sensor revision
+ *     PROC_REG2       sensor id (MSB)
+ *     PROC_REG3       sensor id (LSB)
+ */
+int discam_get_sensor_version(struct v4l2_subdev *sd,
+                             __u16 *id, __u8 *revision);
+
+/*
+ * setup manual integration time.
+ *
+ * integration time given in 100us. A range from 100us (1/10000 s)
+ * up to 6.5 s is possible. value 0 returns DIS_CMD_WRONG_PARAMETER
+ * and does not change the actual setting.
+ *
+ * actual set integration time in 100/256us steps. there's the
+ * ability that the requested integration time could not be set
+ * exactly due to row timing of the sensor. in this case the nearest
+ * possible integration time is setup and returned.
+ *
+ * this function must be called when sensor is in "wakeup" or
+ * "viewfinder" mode. it will wake up sensor first if it is in
+ * "power down" or "standby" mode.
+ *
+ * CMD: DIS_CMD_REQ_ITG_TIME
+ * ARG:        PROC_REG0       -- itg time (MSB)
+ *     PROC_REG1       -- itg time (LSB)
+ * RET:        PROC_REG1 ~ PROC_REG3   -- actual itg time (MSB ~ LSB)
+ */
+int discam_set_itg_time(struct v4l2_subdev *sd,
+                       __u16 time, __u32 *actual_time);
+
+/*
+ * setup manual ISO.
+ *
+ * if an illegal ISO speed value (>1600) is requested,
+ * DIS_CMD_WRONG_PARAMETER retuned.
+ *
+ * return actual ISO speed. there's the  ability that the requested
+ * ISO could not be set exactly due to gain specification of the
+ * sensor. in this case the nearest possible ISO is setup and
+ * returned.
+ *
+ * this function must be called when sensor is in "wakeup" or
+ * "viewfinder" mode. it will wake up sensor first if it is in
+ * "power down" or "standby" mode.
+ *
+ * CMD: DIS_CMD_REQ_ISO_SPEED
+ * ARG:        PROC_REG0       -- ISO (MSB)
+ *     PROC_REG1       -- ISO (LSB)
+ * RET:        PROC_REG1       -- actual ISO (MSB)
+ *     PROC_REG2       -- actual ISO (LSB)
+ */
+int discam_set_iso(struct v4l2_subdev *sd, __u16 iso, __u16 *actual_iso);
+
+/*
+ * setup aperture factor (opening percent)
+ *
+ * this function must be called when sensor is in "wakeup" or
+ * "viewfinder" mode. it will wake up sensor first if it is in
+ * "power down" or "standby" mode.
+ *
+ * valid range: 0~100(0x64), 100 means 100%, fully open.
+ * 0 means closed.
+ *
+ * example:
+ *     F#4.0 ~ 50%
+ *     F#5.6 ~ 25%
+ *
+ * CMD: DIS_CMD_SET_APERTURE_POS
+ * ARG:        PROC_REG0       aperture factor
+ */
+int discam_set_aperture(struct v4l2_subdev *sd, __u8 aperture_factor);
+
+/*
+ * get currently aperture factor (opening percent)
+ *
+ * this function must be called when sensor is in "wakeup" or
+ * "viewfinder" mode. it will wake up sensor first if it is in
+ * "power down" or "standby" mode.
+ *
+ * valid range: 0~100(0x64), 100 means 100%, fully open.
+ * 0 means closed.
+ *
+ * example:
+ *     F#4.0 ~ 50%
+ *     F#5.6 ~ 25%
+ *
+ * CMD: DIS_CMD_GET_APERTURE_POS
+ * RET:        PROC_REG1       aperture factor
+ */
+int discam_get_aperture(struct v4l2_subdev *sd, __u8 *aperture_factor);
+
+/*
+ * get current exposure control settings.
+ *
+ * this function must be called when sensor is in "wakeup" or
+ * "viewfinder" mode. it will wake up sensor first if it is in
+ * "power down" or "standby" mode.
+ *
+ * CMD:        DIS_CMD_GET_EXPOSURE_SETTING
+ * ARG:        PROC_REG0       0x00    -- itg time
+ * RET:        PROC_REG1~PROC_REG3
+ *                     itg time (MSB ~ LSB)
+ *
+ * ARG:        PROC_REG0       0x01    -- ISO
+ * RET:        PROC_REG1~PROC_REG2
+ *                     ISO (MSB ~ LSB)
+ *
+ * ARG:        PROC_REG0       0x05    -- aperture
+ * RET:        PROC_REG1       aperture factor
+ */
+int discam_get_exposure_setting(struct v4l2_subdev *sd,
+                               __u32 *itg_time, __u16 *iso,
+                               __u8 *aperture_factor);
+
+/*
+ * get last snapshot exposure control settings.
+ *
+ * this function must be called when sensor is in "wakeup" or
+ * "viewfinder" mode. it will wake up sensor first if it is in
+ * "power down" or "standby" mode.
+ *
+ * CMD:        DIS_CMD_GET_EXPOSURE_SETTING
+ * ARG:        PROC_REG0       0x10    -- itg time
+ * RET:        PROC_REG1~PROC_REG3
+ *                     itg time (MSB ~ LSB)
+ *
+ * ARG:        PROC_REG0       0x11    -- ISO
+ * RET:        PROC_REG1~PROC_REG2
+ *                     ISO (MSB ~ LSB)
+ *
+ * ARG:        PROC_REG0       0x15    -- aperture
+ * RET:        PROC_REG1       aperture factor
+ */
+int discam_get_last_exposure_setting(struct v4l2_subdev *sd,
+                                    __u32 *itg_time, __u16 *iso,
+                                    __u8 *aperture_factor);
+
+/*
+ * enable shutter usage during snapshot.
+ *
+ * CMD:        DIS_CMD_REQ_SHUTTER_USAGE
+ * ARG:        PROC_REG0:      0x00    -- enable
+ */
+int discam_enable_snapshot_shutter(struct v4l2_subdev *sd);
+
+/*
+ * disable shutter usage during snapshot.
+ *
+ * CMD:        DIS_CMD_REQ_SHUTTER_USAGE
+ * ARG:        PROC_REG0:      0x01    -- disable
+ */
+int discam_disable_snapshot_shutter(struct v4l2_subdev *sd);
+
+/*
+ * select viewfinder exposure setting as snapshot parameters.
+ *
+ * this function must be called when sensor is in "wakeup" or
+ * "viewfinder" mode. it will wake up sensor first if it is in
+ * "power down" or "standby" mode.
+ *
+ * CMD: DIS_CMD_CFG_SNAPSHOT_PARAM
+ * ARG:        PROC_REG0       0x00    -- select snapshot parameter
+ *     PROC_REG1       0x00    -- viewfinder parameters.
+ */
+int discam_config_snapshot_param_vf(struct v4l2_subdev *sd);
+
+/*
+ * set manual exposure setting as snapshot parameters.
+ *
+ * this function must be called when sensor is in "wakeup" or
+ * "viewfinder" mode. it will wake up sensor first if it is in
+ * "power down" or "standby" mode.
+ *
+ * CMD: DIS_CMD_CFG_SNAPSHOT_PARAM
+ * ARG:        PROC_REG0       0x00    -- select snapshot parameter
+ *     PROC_REG1       0x01    -- manual parameters.
+ *
+ *     PROC_REG0       0x01    -- integration time.
+ *     PROC_REG1       itg time (MSB)
+ *     PROC_REG2       itg time (LSB)
+ *
+ *     PROC_REG0       0x02    -- ISO
+ *     PROC_REG1       ISO (MSB)
+ *     PROC_REG2       ISO (LSB)
+ *
+ *     PROC_REG0       0x06    -- aperture factor
+ *     PROC_REG1       aperture factor.
+ */
+int discam_config_snapshot_param_mannual(struct v4l2_subdev *sd,
+                                        __u16 itg_time, __u16 iso,
+                                        __u8 aperture_factor);
+
+/*
+ * request and start viewfinder according to mode.
+ *
+ * CMD: DIS_CMD_REQ_VIEWFINDER
+ * ARG:        PROC_REG0       mode    (valid mode)
+ */
+int discam_start_viewfinder(struct v4l2_subdev *sd, __u8 mode);
+
+/*
+ * stop viewfinder mode.
+ *
+ * CMD: DIS_CMD_REQ_VIEWFINDER
+ * ARG:        PROC_REG0       0x80    -- stop viewfinder
+ */
+int discam_stop_viewfinder(struct v4l2_subdev *sd);
+
+/*
+ * trigger a snapshot image.
+ *
+ * CMD: DIS_CMD_REQ_SNAPSHOT
+ * ARG:        PROC_REG0       mode    (valid mode)
+ */
+int discam_req_snapshot(struct v4l2_subdev *sd, __u8 mode);
+
+/*
+ * Moves the focus motors to the given position.
+ *
+ * CMD:        DIS_CMD_REQ_FOCUS_POS   (Cmd_requestFocusPos)
+ * PROC_REG0:  pos (MSB)
+ * PROC_REG1:  pos (LSB)
+ */
+int discam_req_focus_pos(struct v4l2_subdev *sd, __u16 pos);
+
+/*
+ * get actual focus status and motor position.
+ *
+ * CMD: DIS_CMD_GET_AFSTATUS   (Cmd_getAfStatus)
+ * ARG:        unused
+ * RET:        PROC_REG1       status
+ *     PROC_REG2       pos (MSB)
+ *     PROC_REG3       pos (LSB)
+ */
+int discam_get_af_status(struct v4l2_subdev *sd, __u8 *status, __u16 *pos);
+/*
+ * switch on/off auto focus.
+ *
+ * internal = 0        -- use external AF algorithm
+ * internal != 0 -- use internal AF algorithm
+ *
+ * CMD: DIS_CMD_CFG_AUTO_FOCUS (Cmd_configAutofocus)
+ * ARG:        PROC_REG0:      0x00    Autofocus
+ *     PROC_REG1:      0x00    -- off (manual motor movement,
+ *                             external AF algorithm)
+ *                     0x01    -- on (internal AF algorithm to
+ *                             calculate next motor position)
+ */
+int discam_config_auto_focus(struct v4l2_subdev *sd, int internal);
+/*
+ * config focus range
+ *
+ * CMD: DIS_CMD_CFG_AUTO_FOCUS (Cmd_configAutofocus)
+ * ARG:        PROC_REG0       0x06
+ *     PROC_REG1       0x00    -- normal
+ *                     0x01    -- micro
+ *                     >0x01   -- full range
+ */
+int discam_config_focus_range(struct v4l2_subdev *sd, __u8 range);
+
+/*
+ * start an autofocus sequence. used for internal AF algorithm.
+ *
+ * CMD: DIS_CMD_REQ_AUTO_FOCUS (Cmd_requestAutofocus)
+ * ARG:        PROC_REG0 ~ PROC_REG3: sharpness (MSB~LSB)
+ */
+int discam_req_auto_focus(struct v4l2_subdev *sd, __u32 sharpness);
+
+/*
+ * stops a running autofocus operation, even if it is still
+ * in process.
+ *
+ * CMD:        DIS_CMD_REQ_STOP_AUTO_FOCUS     (Cmd_requestStopAutofocus)
+ */
+int discam_req_stop_auto_focus(struct v4l2_subdev *sd);
+
+/*
+ * functions to read/write specific registers.
+ *
+ * read/write (sensor) register commands can not be called in
+ * "power down" or "standby" mode. these functions will wakeup
+ * sensor first if it is in "power down" or "standby" mode.
+ */
+int discam_write_sensor_register(struct v4l2_subdev *sd, __u16 addr, __u8 data);
+
+int discam_read_sensor_register(struct v4l2_subdev *sd,
+                               __u16 addr, __u8 *data);
+
+int discam_write_register(struct v4l2_subdev *sd, __u16 addr, __u8 data);
+
+int discam_read_register(struct v4l2_subdev *sd, __u16 addr, __u8 *data);
+
+#endif
diff --git a/drivers/media/video/mfld_ci/discam/sensor_com.h b/drivers/media/video/mfld_ci/discam/sensor_com.h
new file mode 100644
index 0000000..f79aeb6
--- /dev/null
+++ b/drivers/media/video/mfld_ci/discam/sensor_com.h
@@ -0,0 +1,152 @@
+/*
+ * Support for Medfield Penwell Camera Imaging ISP subsystem.
+ *
+ * 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.
+ *
+ */
+
+#ifndef        __SENSOR_COM_H__
+#define        __SENSOR_COM_H__
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+/*
+ * if register address or register width is not 32 bit width,
+ * user needs to convert it manually
+ */
+struct __s_register_setting {
+       __u32 reg;
+       __u32 val;
+};
+
+struct __s_output_format {
+       struct v4l2_format v4l2_fmt;
+       int fps;
+};
+
+struct __s_output_format_reg {
+       struct __s_output_format s_fmt;
+       struct __s_register_setting *reg_setting;
+};
+
+#define        __v4l2_format_capture_type_entry(_width, _height, \
+               _pixelformat, _bytesperline, _colorspace) \
+       {\
+               .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,\
+               .fmt.pix.width = (_width),\
+               .fmt.pix.height = (_height),\
+               .fmt.pix.pixelformat = (_pixelformat),\
+               .fmt.pix.bytesperline = (_bytesperline),\
+               .fmt.pix.colorspace = (_colorspace),\
+               .fmt.pix.sizeimage = (_height)*(_bytesperline),\
+       }
+
+#define        __s_output_format_entry(_width, _height, _pixelformat, \
+               _bytesperline, _colorspace, _fps) \
+       {\
+               .v4l2_fmt = __v4l2_format_capture_type_entry(_width, \
+                       _height, _pixelformat, _bytesperline, \
+                               _colorspace),\
+               .fps = (_fps),\
+       }
+
+#define        __s_output_format_reg_entry(_width, _height, _pixelformat, \
+               _bytesperline, _colorspace, _fps, _reg_setting) \
+       {\
+               .s_fmt = __s_output_format_entry(_width, _height,\
+                               _pixelformat, _bytesperline, \
+                               _colorspace, _fps),\
+               .reg_setting = (_reg_setting),\
+       }
+
+struct __s_ctrl_id {
+       struct v4l2_queryctrl qc;
+       int (*s_ctrl) (struct v4l2_subdev *sd, __u32 val);
+       int (*g_ctrl) (struct v4l2_subdev *sd, __u32 *val);
+};
+
+#define        __v4l2_queryctrl_entry_integer(_id, _name,\
+               _minimum, _maximum, _step, \
+               _default_value, _flags) \
+       {\
+               .id = (_id), \
+               .type = V4L2_CTRL_TYPE_INTEGER, \
+               .name = _name, \
+               .minimum = (_minimum), \
+               .maximum = (_maximum), \
+               .step = (_step), \
+               .default_value = (_default_value),\
+               .flags = (_flags),\
+       }
+#define        __v4l2_queryctrl_entry_boolean(_id, _name,\
+               _default_value, _flags) \
+       {\
+               .id = (_id), \
+               .type = V4L2_CTRL_TYPE_BOOLEAN, \
+               .name = _name, \
+               .minimum = 0, \
+               .maximum = 1, \
+               .step = 1, \
+               .default_value = (_default_value),\
+               .flags = (_flags),\
+       }
+
+#define        __s_ctrl_id_entry_integer(_id, _name, \
+               _minimum, _maximum, _step, \
+               _default_value, _flags, \
+               _s_ctrl, _g_ctrl)       \
+       {\
+               .qc = __v4l2_queryctrl_entry_integer(_id, _name,\
+                               _minimum, _maximum, _step,\
+                               _default_value, _flags), \
+               .s_ctrl = _s_ctrl, \
+               .g_ctrl = _g_ctrl, \
+       }
+
+#define        __s_ctrl_id_entry_boolean(_id, _name, \
+               _default_value, _flags, \
+               _s_ctrl, _g_ctrl)       \
+       {\
+               .qc = __v4l2_queryctrl_entry_boolean(_id, _name,\
+                               _default_value, _flags), \
+               .s_ctrl = _s_ctrl, \
+               .g_ctrl = _g_ctrl, \
+       }
+
+/* for debug */
+struct __macro_string {
+       __u8 val;
+       char *string;
+};
+
+#define        __macro_string_entry(VAL)       \
+       {.val = VAL, .string = #VAL}
+
+static inline const char *__macro_to_string(const struct __macro_string *array,
+                                           int size, __u8 val)
+{
+       int i;
+       for (i = 0; i < size; i++) {
+               if (array[i].val == val)
+                       return array[i].string;
+       }
+       return "Unknown VAL";
+}
+
+#endif
diff --git a/drivers/media/video/mfld_ci/discam/to_upstream.h b/drivers/media/video/mfld_ci/discam/to_upstream.h
new file mode 100644
index 0000000..6a998e0
--- /dev/null
+++ b/drivers/media/video/mfld_ci/discam/to_upstream.h
@@ -0,0 +1,37 @@
+/*
+ * Support for Medfield Penwell Camera Imaging ISP subsystem.
+ *
+ * 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.
+ *
+ */
+
+#ifndef        __TO_UPSTREAM_H_
+#define        __TO_UPSTREAM_H_
+
+#include <linux/videodev2.h>
+
+#define V4L2_CID_CAMERA_LASTP1 (V4L2_CID_CAMERA_CLASS_BASE + 22)
+
+#define V4L2_CID_ISO_ABSOLUTE  (V4L2_CID_CAMERA_LASTP1 + 0)
+#define V4L2_CID_APERTURE_ABSOLUTE     (V4L2_CID_CAMERA_LASTP1 + 1)
+#define V4L2_CID_SS_EXPOSURE_ABSOLUTE  (V4L2_CID_CAMERA_LASTP1 + 2)
+#define V4L2_CID_SS_ISO_ABSOLUTE       (V4L2_CID_CAMERA_LASTP1 + 3)
+#define V4L2_CID_SS_APERTURE_ABSOLUTE  (V4L2_CID_CAMERA_LASTP1 + 4)
+#define V4L2_CID_FLASH_DELAY   (V4L2_CID_CAMERA_LASTP1 + 5)
+#define V4L2_CID_FLASH_DURATION        (V4L2_CID_CAMERA_LASTP1 + 6)
+
+#endif
--
1.6.2.5

-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0002-iCDK-primary-camera-dis71430m-sensor-driver-based.patch
Type: application/octet-stream
Size: 114945 bytes
Desc: 0002-iCDK-primary-camera-dis71430m-sensor-driver-based.patch
URL: <http://lists.meego.com/pipermail/meego-kernel/attachments/20101202/744cabc9/attachment-0001.obj>


More information about the MeeGo-kernel mailing list