[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(¶m->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