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

Kristen Carlson Accardi kristen at linux.intel.com
Wed Dec 1 12:56:29 PST 2010


On Thu, 2 Dec 2010 02:52:02 +0800
"Zhang, Xiaolin" <xiaolin.zhang at intel.com> wrote:

> 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)
> +

These macros just make things harder to review.  I think you
should get rid of them, they don't improve readability, and hide
what you are doing.

> +/*
> + * 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);
> +}

A function which has 1 line which just returns the result of another
function is just bloating your code for no value.

> +
> +/*
> + * 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);

I think this function call is just preventing smooth flow of
review - unless you use it elsewhere (and I can't find it if
you do) it's better to just put the code here.
> +
> +       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));
> +}

I think it's better to just call the memset directly.

> +
> +/*
> + *
> + */
> +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
> + */

You have these macros (which do you really need?) defined in
multiple drivers - perhaps you should have some common code.

> +#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
> 



More information about the MeeGo-kernel mailing list