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