nixpkgs_local/linux_surface/patches/0004-cameras.patch

2754 lines
72 KiB
Diff

From 0c7d455e598ee386ffa5ee877d77943a3259f5d6 Mon Sep 17 00:00:00 2001
From: Jake Day <jake@ninebysix.com>
Date: Sun, 27 Jan 2019 10:51:49 -0500
Subject: [PATCH 04/11] cameras
---
drivers/media/usb/uvc/uvc_driver.c | 40 +
drivers/staging/Makefile | 1 +
drivers/staging/ov5693/Kconfig | 10 +
drivers/staging/ov5693/Makefile | 5 +
drivers/staging/ov5693/ad5823.c | 218 +++++
drivers/staging/ov5693/ad5823.h | 90 ++
drivers/staging/ov5693/ov5693.c | 1461 ++++++++++++++++++++++++++++
drivers/staging/ov5693/ov5693.h | 848 ++++++++++++++++
8 files changed, 2673 insertions(+)
create mode 100644 drivers/staging/ov5693/Kconfig
create mode 100644 drivers/staging/ov5693/Makefile
create mode 100644 drivers/staging/ov5693/ad5823.c
create mode 100644 drivers/staging/ov5693/ad5823.h
create mode 100644 drivers/staging/ov5693/ov5693.c
create mode 100644 drivers/staging/ov5693/ov5693.h
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index d46dc432456c..2552fb6fcfbe 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -2352,6 +2352,46 @@ static const struct uvc_device_info uvc_quirk_force_y8 = {
* though they are compliant.
*/
static const struct usb_device_id uvc_ids[] = {
+ /* Microsoft Surface Pro 3 Front */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x045e,
+ .idProduct = 0x07be,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 1 },
+ /* Microsoft Surface Pro 3 Rear */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x045e,
+ .idProduct = 0x07bf,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 1 },
+ /* Microsoft Surface Pro 4 Cam */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x045e,
+ .idProduct = 0x090c,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 1 },
+ /* Microsoft Surface Book Cam 1 */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x045e,
+ .idProduct = 0x090b,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 1 },
+ /* Microsoft Surface Book Cam 2 */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x045e,
+ .idProduct = 0x091a,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 1 },
/* LogiLink Wireless Webcam */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index ab0cbe8815b1..96c4c669a93f 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -53,3 +53,4 @@ obj-$(CONFIG_SOC_MT7621) += mt7621-dts/
obj-$(CONFIG_STAGING_GASKET_FRAMEWORK) += gasket/
obj-$(CONFIG_XIL_AXIS_FIFO) += axis-fifo/
obj-$(CONFIG_EROFS_FS) += erofs/
+obj-$(CONFIG_VIDEO_OV5693) += ov5693/
diff --git a/drivers/staging/ov5693/Kconfig b/drivers/staging/ov5693/Kconfig
new file mode 100644
index 000000000000..96000f112c4d
--- /dev/null
+++ b/drivers/staging/ov5693/Kconfig
@@ -0,0 +1,10 @@
+config VIDEO_OV5693
+ tristate "Omnivision ov5693 sensor support"
+ depends on I2C && VIDEO_V4L2
+ ---help---
+ This is a Video4Linux2 sensor-level driver for the Micron
+ ov5693 5 Mpixel camera.
+
+ ov5693 is video camera sensor.
+
+ It currently only works with the atomisp driver.
diff --git a/drivers/staging/ov5693/Makefile b/drivers/staging/ov5693/Makefile
new file mode 100644
index 000000000000..d8a63faa591f
--- /dev/null
+++ b/drivers/staging/ov5693/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_VIDEO_OV5693) += ov569x.o
+
+ov569x-objs := ov5693.o ad5823.o
+
+ccflags-y += -Werror
diff --git a/drivers/staging/ov5693/ad5823.c b/drivers/staging/ov5693/ad5823.c
new file mode 100644
index 000000000000..7c34c36e77e5
--- /dev/null
+++ b/drivers/staging/ov5693/ad5823.c
@@ -0,0 +1,218 @@
+#include <asm/intel-mid.h>
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/kmod.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-device.h>
+
+#include "ad5823.h"
+
+static struct ad5823_device ad5823_dev;
+static int ad5823_i2c_write(struct i2c_client *client, u8 reg, u8 val)
+{
+ struct i2c_msg msg;
+ u8 buf[2];
+ buf[0] = reg;
+ buf[1] = val;
+ msg.addr = AD5823_VCM_ADDR;
+ msg.flags = 0;
+ msg.len = AD5823_8BIT;
+ msg.buf = &buf[0];
+
+ if (i2c_transfer(client->adapter, &msg, 1) != 1)
+ return -EIO;
+ return 0;
+}
+
+static int ad5823_i2c_read(struct i2c_client *client, u8 reg, u8 *val)
+{
+ struct i2c_msg msg[2];
+ u8 buf[2];
+ buf[0] = reg;
+ buf[1] = 0;
+
+ msg[0].addr = AD5823_VCM_ADDR;
+ msg[0].flags = 0;
+ msg[0].len = AD5823_8BIT;
+ msg[0].buf = &buf[0];
+
+ msg[1].addr = AD5823_VCM_ADDR;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = AD5823_8BIT;
+ msg[1].buf = &buf[1];
+ *val = 0;
+ if (i2c_transfer(client->adapter, msg, 2) != 2)
+ return -EIO;
+ *val = buf[1];
+ return 0;
+}
+
+int ad5823_vcm_power_up(struct v4l2_subdev *sd)
+{
+ int ret = -ENODEV;
+
+ /* Enable power */
+ if (ad5823_dev.platform_data)
+ ret = ad5823_dev.platform_data->power_ctrl(sd, 1);
+ /*
+ * waiting time requested by AD5823(vcm)
+ */
+ usleep_range(1000, 2000);
+ return ret;
+}
+
+int ad5823_vcm_power_down(struct v4l2_subdev *sd)
+{
+ int ret = -ENODEV;
+
+ if (ad5823_dev.platform_data)
+ ret = ad5823_dev.platform_data->power_ctrl(sd, 0);
+
+ return ret;
+}
+
+
+int ad5823_t_focus_vcm(struct v4l2_subdev *sd, u16 val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret = -EINVAL;
+ u8 vcm_code;
+ u8 vcm_mode_reg_val[4] = {
+ AD5823_ARC_RES0,
+ AD5823_ARC_RES1,
+ AD5823_ARC_RES2,
+ AD5823_ESRC
+ };
+
+ if (ad5823_dev.vcm_mode != AD5823_DIRECT) {
+ ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_MSB,
+ AD5823_RING_CTRL_ENABLE);
+ if (ret)
+ return ret;
+
+ ret = ad5823_i2c_write(client, AD5823_REG_MODE,
+ vcm_mode_reg_val[ad5823_dev.vcm_mode]);
+ if (ret)
+ return ret;
+ } else {
+ ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_MSB,
+ AD5823_RING_CTRL_DISABLE);
+ if (ret)
+ return ret;
+ }
+
+ ret = ad5823_i2c_read(client, AD5823_REG_VCM_CODE_MSB, &vcm_code);
+ if (ret)
+ return ret;
+
+ /* set reg VCM_CODE_MSB Bit[1:0] */
+ vcm_code = (vcm_code & VCM_CODE_MSB_MASK) | ((val >> 8) & ~VCM_CODE_MSB_MASK);
+ ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_MSB, vcm_code);
+ if (ret)
+ return ret;
+
+ /* set reg VCM_CODE_LSB Bit[7:0] */
+ ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_LSB,
+ (val & 0x0f));
+ if (ret)
+ return ret;
+
+ /* set required vcm move time */
+ vcm_code = AD5823_RESONANCE_PERIOD / AD5823_RESONANCE_COEF
+ - AD5823_HIGH_FREQ_RANGE;
+ ret = ad5823_i2c_write(client, AD5823_REG_VCM_MOVE_TIME, vcm_code);
+
+ return ret;
+}
+
+int ad5823_t_focus_abs(struct v4l2_subdev *sd, s32 value)
+{
+ int ret;
+
+ value = min(value, AD5823_MAX_FOCUS_POS);
+ ret = ad5823_t_focus_vcm(sd, AD5823_MAX_FOCUS_POS - value);
+ if (ret == 0) {
+ ad5823_dev.number_of_steps = value - ad5823_dev.focus;
+ ad5823_dev.focus = value;
+ ktime_get_ts(&ad5823_dev.timestamp_t_focus_abs);
+ }
+
+ return ret;
+}
+
+int ad5823_t_focus_rel(struct v4l2_subdev *sd, s32 value)
+{
+ return ad5823_t_focus_abs(sd, ad5823_dev.focus + value);
+}
+
+int ad5823_q_focus_status(struct v4l2_subdev *sd, s32 *value)
+{
+ u32 status = 0;
+ struct timespec temptime;
+ const struct timespec timedelay = {
+ 0,
+ min_t(u32, abs(ad5823_dev.number_of_steps)*DELAY_PER_STEP_NS,
+ DELAY_MAX_PER_STEP_NS),
+ };
+
+ ktime_get_ts(&temptime);
+
+ temptime = timespec_sub(temptime, (ad5823_dev.timestamp_t_focus_abs));
+
+ if (timespec_compare(&temptime, &timedelay) <= 0)
+ status = ATOMISP_FOCUS_STATUS_MOVING
+ | ATOMISP_FOCUS_HP_IN_PROGRESS;
+ else
+ status = ATOMISP_FOCUS_STATUS_ACCEPTS_NEW_MOVE
+ | ATOMISP_FOCUS_HP_COMPLETE;
+
+ *value = status;
+
+ return 0;
+}
+
+int ad5823_q_focus_abs(struct v4l2_subdev *sd, s32 *value)
+{
+ s32 val;
+
+ ad5823_q_focus_status(sd, &val);
+
+ if (val & ATOMISP_FOCUS_STATUS_MOVING)
+ *value = ad5823_dev.focus - ad5823_dev.number_of_steps;
+ else
+ *value = ad5823_dev.focus ;
+
+ return 0;
+}
+
+int ad5823_t_vcm_slew(struct v4l2_subdev *sd, s32 value)
+{
+ return 0;
+}
+
+int ad5823_t_vcm_timing(struct v4l2_subdev *sd, s32 value)
+{
+ return 0;
+}
+
+int ad5823_vcm_init(struct v4l2_subdev *sd)
+{
+ /* set vcm mode to ARC RES0.5 */
+ ad5823_dev.vcm_mode = AD5823_ARC_RES1;
+ ad5823_dev.platform_data = camera_get_af_platform_data();
+ return ad5823_dev.platform_data ? 0 : -ENODEV;
+}
diff --git a/drivers/staging/ov5693/ad5823.h b/drivers/staging/ov5693/ad5823.h
new file mode 100644
index 000000000000..8b046c31f3af
--- /dev/null
+++ b/drivers/staging/ov5693/ad5823.h
@@ -0,0 +1,90 @@
+/*
+ * Support for AD5823 VCM.
+ *
+ * Copyright (c) 2013 Intel Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#ifndef __AD5823_H__
+#define __AD5823_H__
+
+#include <linux/atomisp_platform.h>
+#include <linux/types.h>
+
+
+#define AD5823_VCM_ADDR 0x0c
+
+#define AD5823_REG_RESET 0x01
+#define AD5823_REG_MODE 0x02
+#define AD5823_REG_VCM_MOVE_TIME 0x03
+#define AD5823_REG_VCM_CODE_MSB 0x04
+#define AD5823_REG_VCM_CODE_LSB 0x05
+#define AD5823_REG_VCM_THRESHOLD_MSB 0x06
+#define AD5823_REG_VCM_THRESHOLD_LSB 0x07
+
+#define AD5823_RING_CTRL_ENABLE 0x04
+#define AD5823_RING_CTRL_DISABLE 0x00
+
+#define AD5823_RESONANCE_PERIOD 100000
+#define AD5823_RESONANCE_COEF 512
+#define AD5823_HIGH_FREQ_RANGE 0x80
+
+#define VCM_CODE_MSB_MASK 0xfc
+
+enum ad5823_tok_type {
+ AD5823_8BIT = 0x0001,
+ AD5823_16BIT = 0x0002,
+};
+
+enum ad5823_vcm_mode {
+ AD5823_ARC_RES0 = 0x0, /* Actuator response control RES1 */
+ AD5823_ARC_RES1 = 0x1, /* Actuator response control RES0.5 */
+ AD5823_ARC_RES2 = 0x2, /* Actuator response control RES2 */
+ AD5823_ESRC = 0x3, /* Enhanced slew rate control */
+ AD5823_DIRECT = 0x4, /* Direct control */
+};
+
+/* ad5823 device structure */
+struct ad5823_device {
+ struct timespec timestamp_t_focus_abs;
+ enum ad5823_vcm_mode vcm_mode;
+ s16 number_of_steps;
+ bool initialized; /* true if ad5823 is detected */
+ s32 focus; /* Current focus value */
+ struct timespec focus_time; /* Time when focus was last time set */
+ __u8 buffer[4]; /* Used for i2c transactions */
+ const struct camera_af_platform_data *platform_data;
+};
+
+#define AD5823_INVALID_CONFIG 0xffffffff
+#define AD5823_MAX_FOCUS_POS 1023
+
+
+#define DELAY_PER_STEP_NS 1000000
+#define DELAY_MAX_PER_STEP_NS (1000000 * 1023)
+
+int ad5823_vcm_power_up(struct v4l2_subdev *sd);
+int ad5823_vcm_power_down(struct v4l2_subdev *sd);
+int ad5823_vcm_init(struct v4l2_subdev *sd);
+
+int ad5823_t_focus_vcm(struct v4l2_subdev *sd, u16 val);
+int ad5823_t_focus_abs(struct v4l2_subdev *sd, s32 value);
+int ad5823_t_focus_rel(struct v4l2_subdev *sd, s32 value);
+int ad5823_q_focus_status(struct v4l2_subdev *sd, s32 *value);
+int ad5823_q_focus_abs(struct v4l2_subdev *sd, s32 *value);
+
+#endif
diff --git a/drivers/staging/ov5693/ov5693.c b/drivers/staging/ov5693/ov5693.c
new file mode 100644
index 000000000000..51d218da3722
--- /dev/null
+++ b/drivers/staging/ov5693/ov5693.c
@@ -0,0 +1,1461 @@
+/*
+ * Support for OmniVision OV5693 5M HD camera sensor.
+ *
+ * Copyright (c) 2013 Intel Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/kmod.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/moduleparam.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+
+#include "ov5693.h"
+
+/* i2c read/write stuff */
+static int ov5693_read_reg(struct i2c_client *client,
+ u16 data_length, u16 reg, u16 *val)
+{
+ int err;
+ struct i2c_msg msg[2];
+ unsigned char data[6];
+
+ if (!client->adapter) {
+ dev_err(&client->dev, "%s error, no client->adapter\n",
+ __func__);
+ return -ENODEV;
+ }
+
+ if (data_length != OV5693_8BIT && data_length != OV5693_16BIT
+ && data_length != OV5693_32BIT) {
+ dev_err(&client->dev, "%s error, invalid data length\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ memset(msg, 0 , sizeof(msg));
+
+ msg[0].addr = client->addr;
+ msg[0].flags = 0;
+ msg[0].len = I2C_MSG_LENGTH;
+ msg[0].buf = data;
+
+ /* high byte goes out first */
+ data[0] = (u8)(reg >> 8);
+ data[1] = (u8)(reg & 0xff);
+
+ msg[1].addr = client->addr;
+ msg[1].len = data_length;
+ msg[1].flags = I2C_M_RD;
+ msg[1].buf = data;
+
+ err = i2c_transfer(client->adapter, msg, 2);
+ if (err != 2) {
+ if (err >= 0)
+ err = -EIO;
+ dev_err(&client->dev,
+ "read from offset 0x%x error %d", reg, err);
+ return err;
+ }
+
+ *val = 0;
+ /* high byte comes first */
+ if (data_length == OV5693_8BIT)
+ *val = (u8)data[0];
+ else if (data_length == OV5693_16BIT)
+ *val = be16_to_cpu(*(u16 *)&data[0]);
+ else
+ *val = be32_to_cpu(*(u32 *)&data[0]);
+
+ return 0;
+}
+
+static int ov5693_i2c_write(struct i2c_client *client, u16 len, u8 *data)
+{
+ struct i2c_msg msg;
+ const int num_msg = 1;
+ int ret;
+
+ msg.addr = client->addr;
+ msg.flags = 0;
+ msg.len = len;
+ msg.buf = data;
+ ret = i2c_transfer(client->adapter, &msg, 1);
+
+ return ret == num_msg ? 0 : -EIO;
+}
+
+static int ov5693_write_reg(struct i2c_client *client, u16 data_length,
+ u16 reg, u16 val)
+{
+ int ret;
+ unsigned char data[4] = {0};
+ u16 *wreg = (u16 *)data;
+ const u16 len = data_length + sizeof(u16); /* 16-bit address + data */
+
+ if (data_length != OV5693_8BIT && data_length != OV5693_16BIT) {
+ dev_err(&client->dev,
+ "%s error, invalid data_length\n", __func__);
+ return -EINVAL;
+ }
+
+ /* high byte goes out first */
+ *wreg = cpu_to_be16(reg);
+
+ if (data_length == OV5693_8BIT) {
+ data[2] = (u8)(val);
+ } else {
+ /* OV5693_16BIT */
+ u16 *wdata = (u16 *)&data[2];
+ *wdata = cpu_to_be16(val);
+ }
+
+ ret = ov5693_i2c_write(client, len, data);
+ if (ret)
+ dev_err(&client->dev,
+ "write error: wrote 0x%x to offset 0x%x error %d",
+ val, reg, ret);
+
+ return ret;
+}
+
+/*
+ * ov5693_write_reg_array - Initializes a list of OV5693 registers
+ * @client: i2c driver client structure
+ * @reglist: list of registers to be written
+ *
+ * This function initializes a list of registers. When consecutive addresses
+ * are found in a row on the list, this function creates a buffer and sends
+ * consecutive data in a single i2c_transfer().
+ *
+ * __ov5693_flush_reg_array, __ov5693_buf_reg_array() and
+ * __ov5693_write_reg_is_consecutive() are internal functions to
+ * ov5693_write_reg_array_fast() and should be not used anywhere else.
+ *
+ */
+static int __ov5693_flush_reg_array(struct i2c_client *client,
+ struct ov5693_write_ctrl *ctrl)
+{
+ u16 size;
+
+ if (ctrl->index == 0)
+ return 0;
+
+ size = sizeof(u16) + ctrl->index; /* 16-bit address + data */
+ ctrl->buffer.addr = cpu_to_be16(ctrl->buffer.addr);
+ ctrl->index = 0;
+
+ return ov5693_i2c_write(client, size, (u8 *)&ctrl->buffer);
+}
+
+static int __ov5693_buf_reg_array(struct i2c_client *client,
+ struct ov5693_write_ctrl *ctrl,
+ const struct ov5693_reg *next)
+{
+ int size;
+ u16 *data16;
+
+ switch (next->type) {
+ case OV5693_8BIT:
+ size = 1;
+ ctrl->buffer.data[ctrl->index] = (u8)next->val;
+ break;
+ case OV5693_16BIT:
+ size = 2;
+ data16 = (u16 *)&ctrl->buffer.data[ctrl->index];
+ *data16 = cpu_to_be16((u16)next->val);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* When first item is added, we need to store its starting address */
+ if (ctrl->index == 0)
+ ctrl->buffer.addr = next->reg;
+
+ ctrl->index += size;
+
+ /*
+ * Buffer cannot guarantee free space for u32? Better flush it to avoid
+ * possible lack of memory for next item.
+ */
+ if (ctrl->index + sizeof(u16) >= OV5693_MAX_WRITE_BUF_SIZE)
+ return __ov5693_flush_reg_array(client, ctrl);
+
+ return 0;
+}
+
+static int __ov5693_write_reg_is_consecutive(struct i2c_client *client,
+ struct ov5693_write_ctrl *ctrl,
+ const struct ov5693_reg *next)
+{
+ if (ctrl->index == 0)
+ return 1;
+
+ return ctrl->buffer.addr + ctrl->index == next->reg;
+}
+
+static int ov5693_write_reg_array(struct i2c_client *client,
+ const struct ov5693_reg *reglist)
+{
+ const struct ov5693_reg *next = reglist;
+ struct ov5693_write_ctrl ctrl;
+ int err;
+
+ ctrl.index = 0;
+ for (; next->type != OV5693_TOK_TERM; next++) {
+ switch (next->type & OV5693_TOK_MASK) {
+ case OV5693_TOK_DELAY:
+ err = __ov5693_flush_reg_array(client, &ctrl);
+ if (err)
+ return err;
+ usleep_range(next->val * 1000, (next->val + 1) * 1000);
+ break;
+ default:
+ /*
+ * If next address is not consecutive, data needs to be
+ * flushed before proceed.
+ */
+ if (!__ov5693_write_reg_is_consecutive(client, &ctrl,
+ next)) {
+ err = __ov5693_flush_reg_array(client, &ctrl);
+ if (err)
+ return err;
+ }
+ err = __ov5693_buf_reg_array(client, &ctrl, next);
+ if (err) {
+ dev_err(&client->dev, "%s: write error, aborted\n",
+ __func__);
+ return err;
+ }
+ break;
+ }
+ }
+
+ return __ov5693_flush_reg_array(client, &ctrl);
+}
+static int ov5693_g_focal(struct v4l2_subdev *sd, s32 *val)
+{
+ *val = (OV5693_FOCAL_LENGTH_NUM << 16) | OV5693_FOCAL_LENGTH_DEM;
+ return 0;
+}
+
+static int ov5693_g_fnumber(struct v4l2_subdev *sd, s32 *val)
+{
+ /*const f number for ov5693*/
+ *val = (OV5693_F_NUMBER_DEFAULT_NUM << 16) | OV5693_F_NUMBER_DEM;
+ return 0;
+}
+
+static int ov5693_g_fnumber_range(struct v4l2_subdev *sd, s32 *val)
+{
+ *val = (OV5693_F_NUMBER_DEFAULT_NUM << 24) |
+ (OV5693_F_NUMBER_DEM << 16) |
+ (OV5693_F_NUMBER_DEFAULT_NUM << 8) | OV5693_F_NUMBER_DEM;
+ return 0;
+}
+
+
+static int ov5693_get_intg_factor(struct i2c_client *client,
+ struct camera_mipi_info *info,
+ const struct ov5693_resolution *res)
+{
+ struct atomisp_sensor_mode_data *buf = &info->data;
+ unsigned int pix_clk_freq_hz;
+ u16 reg_val;
+ int ret;
+
+ if (info == NULL)
+ return -EINVAL;
+
+ /* pixel clock calculattion */
+ pix_clk_freq_hz = res->pix_clk_freq * 1000000;
+
+ buf->vt_pix_clk_freq_mhz = pix_clk_freq_hz;
+
+ /* get integration time */
+ buf->coarse_integration_time_min = OV5693_COARSE_INTG_TIME_MIN;
+ buf->coarse_integration_time_max_margin =
+ OV5693_COARSE_INTG_TIME_MAX_MARGIN;
+
+ buf->fine_integration_time_min = OV5693_FINE_INTG_TIME_MIN;
+ buf->fine_integration_time_max_margin =
+ OV5693_FINE_INTG_TIME_MAX_MARGIN;
+
+ buf->fine_integration_time_def = OV5693_FINE_INTG_TIME_MIN;
+ buf->frame_length_lines = res->lines_per_frame;
+ buf->line_length_pck = res->pixels_per_line;
+ buf->read_mode = res->bin_mode;
+
+ /* get the cropping and output resolution to ISP for this mode. */
+ ret = ov5693_read_reg(client, OV5693_16BIT,
+ OV5693_H_CROP_START_H, &reg_val);
+ if (ret)
+ return ret;
+ buf->crop_horizontal_start = reg_val;
+
+ ret = ov5693_read_reg(client, OV5693_16BIT,
+ OV5693_V_CROP_START_H, &reg_val);
+ if (ret)
+ return ret;
+ buf->crop_vertical_start = reg_val;
+
+ ret = ov5693_read_reg(client, OV5693_16BIT,
+ OV5693_H_CROP_END_H, &reg_val);
+ if (ret)
+ return ret;
+ buf->crop_horizontal_end = reg_val;
+
+ ret = ov5693_read_reg(client, OV5693_16BIT,
+ OV5693_V_CROP_END_H, &reg_val);
+ if (ret)
+ return ret;
+ buf->crop_vertical_end = reg_val;
+
+ ret = ov5693_read_reg(client, OV5693_16BIT,
+ OV5693_H_OUTSIZE_H, &reg_val);
+ if (ret)
+ return ret;
+ buf->output_width = reg_val;
+
+ ret = ov5693_read_reg(client, OV5693_16BIT,
+ OV5693_V_OUTSIZE_H, &reg_val);
+ if (ret)
+ return ret;
+ buf->output_height = reg_val;
+
+ /*
+ * we can't return 0 for bin_factor, this is because camera
+ * HAL will use them as denominator, bin_factor = 0 will
+ * cause camera HAL crash. So we return bin_factor as this
+ * rules:
+ * [1]. res->bin_factor = 0, return 1 for bin_factor.
+ * [2]. res->bin_factor > 0, return res->bin_factor.
+ */
+ buf->binning_factor_x = res->bin_factor_x ?
+ res->bin_factor_x : 1;
+ buf->binning_factor_y = res->bin_factor_y ?
+ res->bin_factor_y : 1;
+ return 0;
+}
+
+static long __ov5693_set_exposure(struct v4l2_subdev *sd, int coarse_itg,
+ int gain, int digitgain)
+
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ u16 vts;
+ int ret;
+
+ /*
+ * According to spec, the low 4 bits of exposure/gain reg are
+ * fraction bits, so need to take 4 bits left shift to align
+ * reg integer bits.
+ */
+ coarse_itg <<= 4;
+ gain <<= 4;
+
+ ret = ov5693_read_reg(client, OV5693_16BIT,
+ OV5693_VTS_H, &vts);
+ if (ret)
+ return ret;
+
+ if (coarse_itg + OV5693_INTEGRATION_TIME_MARGIN >= vts)
+ vts = coarse_itg + OV5693_INTEGRATION_TIME_MARGIN;
+
+ ret = ov5693_write_reg(client, OV5693_16BIT, OV5693_VTS_H, vts);
+ if (ret)
+ return ret;
+
+ /* group hold start */
+ ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_GROUP_ACCESS, 0);
+ if (ret)
+ return ret;
+
+ /* set exposure */
+ ret = ov5693_write_reg(client, OV5693_8BIT,
+ OV5693_AEC_PK_EXPO_L,
+ coarse_itg & 0xff);
+ if (ret)
+ return ret;
+
+ ret = ov5693_write_reg(client, OV5693_16BIT,
+ OV5693_AEC_PK_EXPO_H,
+ (coarse_itg >> 8) & 0xfff);
+ if (ret)
+ return ret;
+
+ /* set analog gain */
+ ret = ov5693_write_reg(client, OV5693_16BIT,
+ OV5693_AGC_ADJ_H, gain);
+ if (ret)
+ return ret;
+
+ /* set digital gain */
+ ret = ov5693_write_reg(client, OV5693_16BIT,
+ OV5693_MWB_GAIN_R_H, digitgain);
+ if (ret)
+ return ret;
+
+ ret = ov5693_write_reg(client, OV5693_16BIT,
+ OV5693_MWB_GAIN_G_H, digitgain);
+ if (ret)
+ return ret;
+
+ ret = ov5693_write_reg(client, OV5693_16BIT,
+ OV5693_MWB_GAIN_B_H, digitgain);
+ if (ret)
+ return ret;
+
+ /* group hold end */
+ ret = ov5693_write_reg(client, OV5693_8BIT,
+ OV5693_GROUP_ACCESS, 0x10);
+ if (ret)
+ return ret;
+
+ /* group hold launch */
+ ret = ov5693_write_reg(client, OV5693_8BIT,
+ OV5693_GROUP_ACCESS, 0xa0);
+
+ return ret;
+}
+
+static int ov5693_set_exposure(struct v4l2_subdev *sd, int exposure,
+ int gain, int digitgain)
+{
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+ int ret;
+
+ mutex_lock(&dev->input_lock);
+ ret = __ov5693_set_exposure(sd, exposure, gain, digitgain);
+ mutex_unlock(&dev->input_lock);
+
+ return ret;
+}
+
+static long ov5693_s_exposure(struct v4l2_subdev *sd,
+ struct atomisp_exposure *exposure)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int exp = exposure->integration_time[0];
+ int gain = exposure->gain[0];
+ int digitgain = exposure->gain[1];
+
+ /* we should not accept the invalid value below. */
+ if (gain == 0) {
+ dev_err(&client->dev, "%s: invalid value\n", __func__);
+ return -EINVAL;
+ }
+
+ return ov5693_set_exposure(sd, exp, gain, digitgain);
+}
+
+static long ov5693_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+
+ switch (cmd) {
+ case ATOMISP_IOC_S_EXPOSURE:
+ return ov5693_s_exposure(sd, arg);
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* This returns the exposure time being used. This should only be used
+ for filling in EXIF data, not for actual image processing. */
+static int ov5693_q_exposure(struct v4l2_subdev *sd, s32 *value)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ u16 reg_v, reg_v2;
+ int ret;
+
+ /* get exposure */
+ ret = ov5693_read_reg(client, OV5693_8BIT,
+ OV5693_AEC_PK_EXPO_L,
+ &reg_v);
+ if (ret)
+ goto err;
+
+ ret = ov5693_read_reg(client, OV5693_8BIT,
+ OV5693_AEC_PK_EXPO_M,
+ &reg_v2);
+ if (ret)
+ goto err;
+
+ reg_v += reg_v2 << 8;
+ ret = ov5693_read_reg(client, OV5693_8BIT,
+ OV5693_AEC_PK_EXPO_H,
+ &reg_v2);
+ if (ret)
+ goto err;
+
+ *value = (reg_v + (((u32)reg_v2 << 16))) >> 4;
+err:
+ return ret;
+}
+
+/*
+ * This below focus func don't need input_lock mutex_lock
+ * since they are just called in v4l2 s_ctrl/g_ctrl framework
+ * where mutex input_lock have been done.
+ */
+int ov5693_t_focus_abs(struct v4l2_subdev *sd, s32 value)
+{
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+ int ret = 0;
+
+ if (dev->vcm_driver && dev->vcm_driver->t_focus_abs)
+ ret = dev->vcm_driver->t_focus_abs(sd, value);
+
+ return ret;
+}
+
+int ov5693_t_focus_rel(struct v4l2_subdev *sd, s32 value)
+{
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+ int ret = 0;
+
+ if (dev->vcm_driver && dev->vcm_driver->t_focus_rel)
+ ret = dev->vcm_driver->t_focus_rel(sd, value);
+
+ return ret;
+}
+
+int ov5693_q_focus_status(struct v4l2_subdev *sd, s32 *value)
+{
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+ int ret = 0;
+
+ if (dev->vcm_driver && dev->vcm_driver->q_focus_status)
+ ret = dev->vcm_driver->q_focus_status(sd, value);
+
+ return ret;
+}
+
+int ov5693_q_focus_abs(struct v4l2_subdev *sd, s32 *value)
+{
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+ int ret = 0;
+
+ if (dev->vcm_driver && dev->vcm_driver->q_focus_abs)
+ ret = dev->vcm_driver->q_focus_abs(sd, value);
+
+ return ret;
+}
+
+/* ov5693 control set/get */
+static int ov5693_g_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct ov5693_device *dev = container_of(
+ ctrl->handler, struct ov5693_device, ctrl_handler);
+ int ret = 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_EXPOSURE_ABSOLUTE:
+ ret = ov5693_q_exposure(&dev->sd, &ctrl->val);
+ break;
+ case V4L2_CID_FOCUS_ABSOLUTE:
+ ret = ov5693_q_focus_abs(&dev->sd, &ctrl->val);
+ break;
+ case V4L2_CID_FOCUS_STATUS:
+ ret = ov5693_q_focus_status(&dev->sd, &ctrl->val);
+ break;
+ case V4L2_CID_FOCAL_ABSOLUTE:
+ ret = ov5693_g_focal(&dev->sd, &ctrl->val);
+ break;
+ case V4L2_CID_FNUMBER_ABSOLUTE:
+ ret = ov5693_g_fnumber(&dev->sd, &ctrl->val);
+ break;
+ case V4L2_CID_FNUMBER_RANGE:
+ ret = ov5693_g_fnumber_range(&dev->sd, &ctrl->val);
+ break;
+ case V4L2_CID_BIN_FACTOR_HORZ:
+ ctrl->val = dev->ov5693_res[dev->fmt_idx].bin_factor_x;
+ break;
+ case V4L2_CID_BIN_FACTOR_VERT:
+ ctrl->val = dev->ov5693_res[dev->fmt_idx].bin_factor_y;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int ov5693_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct ov5693_device *dev = container_of(
+ ctrl->handler, struct ov5693_device, ctrl_handler);
+ int ret = 0;
+
+ if (!ctrl)
+ return -EINVAL;
+
+ switch (ctrl->id) {
+ case V4L2_CID_RUN_MODE:
+ switch (ctrl->val) {
+ case ATOMISP_RUN_MODE_VIDEO:
+ dev->ov5693_res = ov5693_res_video;
+ dev->curr_res_num = N_RES_VIDEO;
+ break;
+ case ATOMISP_RUN_MODE_STILL_CAPTURE:
+ dev->ov5693_res = ov5693_res_still;
+ dev->curr_res_num = N_RES_STILL;
+ break;
+ default:
+ dev->ov5693_res = ov5693_res_preview;
+ dev->curr_res_num = N_RES_PREVIEW;
+ }
+ break;
+ case V4L2_CID_FOCUS_ABSOLUTE:
+ ret = ov5693_t_focus_abs(&dev->sd, ctrl->val);
+ break;
+ case V4L2_CID_FOCUS_RELATIVE:
+ ret = ov5693_t_focus_rel(&dev->sd, ctrl->val);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int ov5693_init(struct v4l2_subdev *sd)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+ int ret = 0;
+
+ /* restore settings */
+ dev->ov5693_res = ov5693_res_preview;
+ dev->curr_res_num = N_RES_PREVIEW;
+
+ ret = ov5693_write_reg_array(client, ov5693_init_setting);
+ if (ret)
+ dev_err(&client->dev, "ov5693 write init setting reg err.\n");
+
+ return ret;
+}
+
+
+static int power_up(struct v4l2_subdev *sd)
+{
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+
+ if (NULL == dev->platform_data) {
+ dev_err(&client->dev,
+ "no camera_sensor_platform_data");
+ return -ENODEV;
+ }
+
+ /* power control */
+ ret = dev->platform_data->power_ctrl(sd, 1);
+ if (ret)
+ goto fail_power;
+
+ /* gpio ctrl */
+ ret = dev->platform_data->gpio_ctrl(sd, 1);
+ if (ret)
+ goto fail_power;
+
+ /* flis clock control */
+ ret = dev->platform_data->flisclk_ctrl(sd, 1);
+ if (ret)
+ goto fail_clk;
+
+ /* according to DS, 20ms is needed between PWDN and i2c access */
+ msleep(20);
+
+ return 0;
+
+fail_clk:
+ dev->platform_data->gpio_ctrl(sd, 0);
+fail_power:
+ dev->platform_data->power_ctrl(sd, 0);
+ dev_err(&client->dev, "sensor power-up failed\n");
+
+ return ret;
+}
+
+static int power_down(struct v4l2_subdev *sd)
+{
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret = 0;
+
+ if (NULL == dev->platform_data) {
+ dev_err(&client->dev,
+ "no camera_sensor_platform_data");
+ return -ENODEV;
+ }
+
+ ret = dev->platform_data->flisclk_ctrl(sd, 0);
+ if (ret)
+ dev_err(&client->dev, "flisclk failed\n");
+
+ /* gpio ctrl */
+ ret = dev->platform_data->gpio_ctrl(sd, 0);
+ if (ret)
+ dev_err(&client->dev, "gpio failed.\n");
+
+ /* power control */
+ ret = dev->platform_data->power_ctrl(sd, 0);
+ if (ret)
+ dev_err(&client->dev, "vprog failed.\n");
+
+ return ret;
+}
+
+static int ov5693_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret = 0;
+
+ mutex_lock(&dev->input_lock);
+ if (on == 0) {
+ if (dev->vcm_driver && dev->vcm_driver->power_down)
+ ret = dev->vcm_driver->power_down(sd);
+ if (ret)
+ dev_err(&client->dev, "vcm power-down failed.\n");
+
+ ret = power_down(sd);
+ } else {
+ if (dev->vcm_driver && dev->vcm_driver->power_up)
+ ret = dev->vcm_driver->power_up(sd);
+ if (ret)
+ dev_err(&client->dev, "vcm power-up failed.\n");
+
+ ret = power_up(sd);
+ if (!ret)
+ ret = ov5693_init(sd);
+ }
+ mutex_unlock(&dev->input_lock);
+ return ret;
+}
+
+/*
+ * distance - calculate the distance
+ * @res: resolution
+ * @w: width
+ * @h: height
+ *
+ * Get the gap between resolution and w/h.
+ * res->width/height smaller than w/h wouldn't be considered.
+ * Returns the value of gap or -1 if fail.
+ */
+static int distance(struct ov5693_resolution *res, u32 w, u32 h)
+{
+ unsigned int w_ratio = ((res->width << RATIO_SHIFT_BITS)/w);
+ unsigned int h_ratio;
+ int match;
+
+ if (h == 0)
+ return -1;
+ h_ratio = ((res->height << RATIO_SHIFT_BITS) / h);
+ if (h_ratio == 0)
+ return -1;
+ match = abs(((w_ratio << RATIO_SHIFT_BITS) / h_ratio)
+ - ((int)(1 << RATIO_SHIFT_BITS)));
+
+ if ((w_ratio < (int)(1 << RATIO_SHIFT_BITS))
+ || (h_ratio < (int)(1 << RATIO_SHIFT_BITS)) ||
+ (match > LARGEST_ALLOWED_RATIO_MISMATCH))
+ return -1;
+
+ return w_ratio + h_ratio;
+}
+
+/* Return the nearest higher resolution index */
+static int nearest_resolution_index(struct v4l2_subdev *sd,
+ int w, int h)
+{
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+ int i;
+ int idx = dev->curr_res_num-1;
+ int dist;
+ int min_dist = INT_MAX;
+ struct ov5693_resolution *tmp_res = NULL;
+
+ for (i = 0; i < dev->curr_res_num; i++) {
+ tmp_res = &dev->ov5693_res[i];
+ dist = distance(tmp_res, w, h);
+ if (dist == -1)
+ continue;
+ if (dist < min_dist) {
+ min_dist = dist;
+ idx = i;
+ }
+ }
+
+ return idx;
+}
+
+static int get_resolution_index(struct v4l2_subdev *sd,
+ int w, int h)
+{
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+ int i;
+
+ for (i = 0; i < dev->curr_res_num; i++) {
+ if (w != dev->ov5693_res[i].width)
+ continue;
+ if (h != dev->ov5693_res[i].height)
+ continue;
+
+ return i;
+ }
+
+ return -1;
+}
+
+static int __ov5693_try_mbus_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *fmt)
+{
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+ int idx;
+
+ if (!fmt)
+ return -EINVAL;
+
+ idx = nearest_resolution_index(sd, fmt->width, fmt->height);
+ fmt->width = dev->ov5693_res[idx].width;
+ fmt->height = dev->ov5693_res[idx].height;
+ fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+
+ return 0;
+}
+
+static int ov5693_try_mbus_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *fmt)
+{
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+ int ret;
+
+ mutex_lock(&dev->input_lock);
+ ret = __ov5693_try_mbus_fmt(sd, fmt);
+ mutex_unlock(&dev->input_lock);
+
+ return ret;
+}
+
+static int ov5693_s_mbus_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *fmt)
+{
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct camera_mipi_info *ov5693_info = NULL;
+ int ret = 0;
+
+ ov5693_info = v4l2_get_subdev_hostdata(sd);
+ if (ov5693_info == NULL)
+ return -EINVAL;
+
+ mutex_lock(&dev->input_lock);
+ ret = __ov5693_try_mbus_fmt(sd, fmt);
+ if (ret == -1) {
+ dev_err(&client->dev, "try fmt fail\n");
+ goto done;
+ }
+
+ dev->fmt_idx = get_resolution_index(sd, fmt->width, fmt->height);
+ if (dev->fmt_idx == -1) {
+ dev_err(&client->dev, "get resolution fail\n");
+ goto done;
+ }
+
+ ret = ov5693_write_reg_array(client, dev->ov5693_res[dev->fmt_idx].regs);
+ if (ret) {
+ dev_err(&client->dev, "ov5693 write fmt register err.\n");
+ goto done;
+ }
+
+ ret = ov5693_get_intg_factor(client, ov5693_info,
+ &dev->ov5693_res[dev->fmt_idx]);
+ if (ret)
+ dev_err(&client->dev, "failed to get integration_factor\n");
+
+done:
+ mutex_unlock(&dev->input_lock);
+ return ret;
+}
+static int ov5693_g_mbus_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *fmt)
+{
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+
+ mutex_lock(&dev->input_lock);
+ fmt->width = dev->ov5693_res[dev->fmt_idx].width;
+ fmt->height = dev->ov5693_res[dev->fmt_idx].height;
+ fmt->code = V4L2_MBUS_FMT_SBGGR10_1X10;
+ mutex_unlock(&dev->input_lock);
+
+ return 0;
+}
+
+static int ov5693_detect(struct i2c_client *client)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ int ret = 0;
+ u16 id;
+ u8 revision;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
+ return -ENODEV;
+
+ ret = ov5693_read_reg(client, OV5693_16BIT,
+ OV5693_SC_CMMN_CHIP_ID, &id);
+ if (ret) {
+ dev_err(&client->dev, "read sensor_id err.\n");
+ return -ENODEV;
+ }
+
+ if (id != OV5693_ID) {
+ dev_err(&client->dev, "sensor ID error\n");
+ return -ENODEV;
+ }
+
+ ret = ov5693_read_reg(client, OV5693_8BIT,
+ OV5693_SC_CMMN_SUB_ID, &id);
+ revision = (u8)id & 0x0f;
+
+ dev_dbg(&client->dev, "sensor_revision = 0x%x\n", revision);
+ dev_dbg(&client->dev, "detect ov5693 success\n");
+ return ret;
+}
+
+static int ov5693_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+
+ mutex_lock(&dev->input_lock);
+
+ ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_SW_STREAM,
+ enable ? OV5693_START_STREAMING :
+ OV5693_STOP_STREAMING);
+
+ mutex_unlock(&dev->input_lock);
+ return ret;
+}
+
+/* ov5693 enum frame size, frame intervals */
+static int ov5693_enum_framesizes(struct v4l2_subdev *sd,
+ struct v4l2_frmsizeenum *fsize)
+{
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+ unsigned int index = fsize->index;
+
+ mutex_lock(&dev->input_lock);
+
+ if (index >= dev->curr_res_num) {
+ mutex_unlock(&dev->input_lock);
+ return -EINVAL;
+ }
+
+ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+ fsize->discrete.width = dev->ov5693_res[index].width;
+ fsize->discrete.height = dev->ov5693_res[index].height;
+
+ mutex_unlock(&dev->input_lock);
+ return 0;
+}
+
+static int ov5693_enum_frameintervals(struct v4l2_subdev *sd,
+ struct v4l2_frmivalenum *fival)
+{
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+ unsigned int index = fival->index;
+
+ mutex_lock(&dev->input_lock);
+
+ if (index >= dev->curr_res_num) {
+ mutex_unlock(&dev->input_lock);
+ return -EINVAL;
+ }
+
+ fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+ fival->width = dev->ov5693_res[index].width;
+ fival->height = dev->ov5693_res[index].height;
+ fival->discrete.numerator = 1;
+ fival->discrete.denominator = dev->ov5693_res[index].fps;
+
+ mutex_unlock(&dev->input_lock);
+
+ return 0;
+}
+
+static int ov5693_enum_mbus_fmt(struct v4l2_subdev *sd,
+ unsigned int index,
+ enum v4l2_mbus_pixelcode *code)
+{
+ *code = V4L2_MBUS_FMT_SBGGR10_1X10;
+
+ return 0;
+}
+
+static int ov5693_s_config(struct v4l2_subdev *sd,
+ int irq, void *platform_data)
+{
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret = 0;
+
+ if (platform_data == NULL)
+ return -ENODEV;
+
+ mutex_lock(&dev->input_lock);
+
+ dev->platform_data = platform_data;
+
+ ret = power_up(sd);
+ if (ret) {
+ dev_err(&client->dev, "ov5693 power-up err.\n");
+ goto fail_power_on;
+ }
+
+ ret = dev->platform_data->csi_cfg(sd, 1);
+ if (ret)
+ goto fail_csi_cfg;
+
+ /* config & detect sensor */
+ ret = ov5693_detect(client);
+ if (ret) {
+ dev_err(&client->dev, "ov5693_detect err s_config.\n");
+ goto fail_csi_cfg;
+ }
+
+ /* turn off sensor, after probed */
+ ret = power_down(sd);
+ if (ret) {
+ dev_err(&client->dev, "ov5693 power-off err.\n");
+ goto fail_csi_cfg;
+ }
+ mutex_unlock(&dev->input_lock);
+
+ return 0;
+
+fail_csi_cfg:
+ dev->platform_data->csi_cfg(sd, 0);
+fail_power_on:
+ power_down(sd);
+ dev_err(&client->dev, "sensor power-gating failed\n");
+ mutex_unlock(&dev->input_lock);
+ return ret;
+}
+
+static int ov5693_g_parm(struct v4l2_subdev *sd,
+ struct v4l2_streamparm *param)
+{
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ dev_err(&client->dev, "unsupported buffer type.\n");
+ return -EINVAL;
+ }
+
+ memset(param, 0, sizeof(*param));
+ param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ mutex_lock(&dev->input_lock);
+ if (dev->fmt_idx >= 0 && dev->fmt_idx < dev->curr_res_num) {
+ param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+ param->parm.capture.timeperframe.numerator = 1;
+ param->parm.capture.capturemode = dev->run_mode->val;
+ param->parm.capture.timeperframe.denominator =
+ dev->ov5693_res[dev->fmt_idx].fps;
+ }
+ mutex_unlock(&dev->input_lock);
+ return 0;
+}
+
+static int ov5693_g_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *interval)
+{
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+
+ mutex_lock(&dev->input_lock);
+ interval->interval.numerator = 1;
+ interval->interval.denominator = dev->ov5693_res[dev->fmt_idx].fps;
+ mutex_unlock(&dev->input_lock);
+
+ return 0;
+}
+
+static int ov5693_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ code->code = V4L2_MBUS_FMT_SBGGR10_1X10;
+ return 0;
+}
+
+static int ov5693_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+ int index = fse->index;
+
+ mutex_lock(&dev->input_lock);
+
+ if (index >= dev->curr_res_num) {
+ mutex_unlock(&dev->input_lock);
+ return -EINVAL;
+ }
+
+ fse->min_width = dev->ov5693_res[index].width;
+ fse->min_height = dev->ov5693_res[index].height;
+ fse->max_width = dev->ov5693_res[index].width;
+ fse->max_height = dev->ov5693_res[index].height;
+
+ mutex_unlock(&dev->input_lock);
+ return 0;
+}
+
+static int ov5693_get_pad_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+ struct v4l2_mbus_framefmt *format;
+
+ mutex_lock(&dev->input_lock);
+
+ switch (fmt->which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ format = v4l2_subdev_get_try_format(fh, fmt->pad);
+ break;
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ format = &dev->format;
+ break;
+ default:
+ format = NULL;
+ }
+
+ mutex_unlock(&dev->input_lock);
+
+ if (!format)
+ return -EINVAL;
+
+ fmt->format = *format;
+ return 0;
+}
+
+static int ov5693_set_pad_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+
+ mutex_lock(&dev->input_lock);
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+ dev->format = fmt->format;
+
+ mutex_unlock(&dev->input_lock);
+ return 0;
+}
+
+static int ov5693_g_skip_frames(struct v4l2_subdev *sd, u32 *frames)
+{
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+
+ mutex_lock(&dev->input_lock);
+ *frames = dev->ov5693_res[dev->fmt_idx].skip_frames;
+ mutex_unlock(&dev->input_lock);
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops ctrl_ops = {
+ .s_ctrl = ov5693_s_ctrl,
+ .g_volatile_ctrl = ov5693_g_ctrl,
+};
+
+static const char * const ctrl_run_mode_menu[] = {
+ NULL,
+ "Video",
+ "Still capture",
+ "Continuous capture",
+ "Preview",
+};
+
+static const struct v4l2_ctrl_config ctrl_run_mode = {
+ .ops = &ctrl_ops,
+ .id = V4L2_CID_RUN_MODE,
+ .name = "run mode",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .min = 1,
+ .def = 4,
+ .max = 4,
+ .qmenu = ctrl_run_mode_menu,
+};
+
+static const struct v4l2_ctrl_config ctrls[] = {
+ {
+ .ops = &ctrl_ops,
+ .id = V4L2_CID_EXPOSURE_ABSOLUTE,
+ .name = "absolute exposure",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 0x0,
+ .max = 0xffff,
+ .step = 0x01,
+ .def = 0x00,
+ .flags = 0,
+ }, {
+ .ops = &ctrl_ops,
+ .id = V4L2_CID_FOCUS_ABSOLUTE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "focus move absolute",
+ .min = 0,
+ .max = OV5693_MAX_FOCUS_POS,
+ .step = 1,
+ .def = 0,
+ .flags = 0,
+ }, {
+ .ops = &ctrl_ops,
+ .id = V4L2_CID_FOCUS_RELATIVE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "focus move relative",
+ .min = OV5693_MAX_FOCUS_NEG,
+ .max = OV5693_MAX_FOCUS_POS,
+ .step = 1,
+ .def = 0,
+ .flags = 0,
+ }, {
+ .ops = &ctrl_ops,
+ .id = V4L2_CID_FOCUS_STATUS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "focus status",
+ .min = 0,
+ .max = 100,
+ .step = 1,
+ .def = 0,
+ .flags = 0,
+ }, {
+ .ops = &ctrl_ops,
+ .id = V4L2_CID_FOCAL_ABSOLUTE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "focal length",
+ .min = OV5693_FOCAL_LENGTH_DEFAULT,
+ .max = OV5693_FOCAL_LENGTH_DEFAULT,
+ .step = 0x01,
+ .def = OV5693_FOCAL_LENGTH_DEFAULT,
+ .flags = 0,
+ }, {
+ .ops = &ctrl_ops,
+ .id = V4L2_CID_FNUMBER_ABSOLUTE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "f-number",
+ .min = OV5693_F_NUMBER_DEFAULT,
+ .max = OV5693_F_NUMBER_DEFAULT,
+ .step = 0x01,
+ .def = OV5693_F_NUMBER_DEFAULT,
+ .flags = 0,
+ }, {
+ .ops = &ctrl_ops,
+ .id = V4L2_CID_FNUMBER_RANGE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "f-number range",
+ .min = OV5693_F_NUMBER_RANGE,
+ .max = OV5693_F_NUMBER_RANGE,
+ .step = 0x01,
+ .def = OV5693_F_NUMBER_RANGE,
+ .flags = 0,
+ }, {
+ .ops = &ctrl_ops,
+ .id = V4L2_CID_BIN_FACTOR_HORZ,
+ .name = "horizontal binning factor",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .max = OV5693_BIN_FACTOR_MAX,
+ .step = 2,
+ .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE,
+ }, {
+ .ops = &ctrl_ops,
+ .id = V4L2_CID_BIN_FACTOR_VERT,
+ .name = "vertical binning factor",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .max = OV5693_BIN_FACTOR_MAX,
+ .step = 2,
+ .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_VOLATILE,
+ }
+};
+
+static const struct v4l2_subdev_sensor_ops ov5693_sensor_ops = {
+ .g_skip_frames = ov5693_g_skip_frames,
+};
+
+static const struct v4l2_subdev_video_ops ov5693_video_ops = {
+ .s_stream = ov5693_s_stream,
+ .g_parm = ov5693_g_parm,
+ .enum_framesizes = ov5693_enum_framesizes,
+ .enum_frameintervals = ov5693_enum_frameintervals,
+ .enum_mbus_fmt = ov5693_enum_mbus_fmt,
+ .try_mbus_fmt = ov5693_try_mbus_fmt,
+ .g_mbus_fmt = ov5693_g_mbus_fmt,
+ .s_mbus_fmt = ov5693_s_mbus_fmt,
+ .g_frame_interval = ov5693_g_frame_interval,
+};
+
+static const struct v4l2_subdev_core_ops ov5693_core_ops = {
+ .s_power = ov5693_s_power,
+ .queryctrl = v4l2_subdev_queryctrl,
+ .g_ctrl = v4l2_subdev_g_ctrl,
+ .s_ctrl = v4l2_subdev_s_ctrl,
+ .ioctl = ov5693_ioctl,
+};
+
+static const struct v4l2_subdev_pad_ops ov5693_pad_ops = {
+ .enum_mbus_code = ov5693_enum_mbus_code,
+ .enum_frame_size = ov5693_enum_frame_size,
+ .get_fmt = ov5693_get_pad_format,
+ .set_fmt = ov5693_set_pad_format,
+};
+
+static const struct v4l2_subdev_ops ov5693_ops = {
+ .core = &ov5693_core_ops,
+ .video = &ov5693_video_ops,
+ .pad = &ov5693_pad_ops,
+ .sensor = &ov5693_sensor_ops,
+};
+
+static int ov5693_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ov5693_device *dev = to_ov5693_sensor(sd);
+ dev_dbg(&client->dev, "ov5693_remove...\n");
+
+ dev->platform_data->csi_cfg(sd, 0);
+
+ v4l2_device_unregister_subdev(sd);
+ media_entity_cleanup(&dev->sd.entity);
+ devm_kfree(&client->dev, dev);
+
+ return 0;
+}
+
+static int ov5693_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct ov5693_device *dev;
+ int i;
+ int ret;
+
+ dev = devm_kzalloc(&client->dev, sizeof(*dev), GFP_KERNEL);
+ if (!dev) {
+ dev_err(&client->dev, "out of memory\n");
+ return -ENOMEM;
+ }
+
+ mutex_init(&dev->input_lock);
+
+ /*
+ * Initialize related res members of dev.
+ */
+ dev->fmt_idx = 0;
+ dev->ov5693_res = ov5693_res_preview;
+ dev->curr_res_num = N_RES_PREVIEW;
+
+ v4l2_i2c_subdev_init(&(dev->sd), client, &ov5693_ops);
+
+ if (client->dev.platform_data) {
+ ret = ov5693_s_config(&dev->sd, client->irq,
+ client->dev.platform_data);
+ if (ret)
+ goto out_free;
+ }
+
+ dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ dev->pad.flags = MEDIA_PAD_FL_SOURCE;
+ dev->format.code = V4L2_MBUS_FMT_SBGGR10_1X10;
+ dev->sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
+ dev->vcm_driver = &ov5693_vcm_ops;
+
+ ret = v4l2_ctrl_handler_init(&dev->ctrl_handler, ARRAY_SIZE(ctrls) + 1);
+ if (ret) {
+ ov5693_remove(client);
+ return ret;
+ }
+
+ dev->run_mode = v4l2_ctrl_new_custom(&dev->ctrl_handler,
+ &ctrl_run_mode, NULL);
+
+ for (i = 0; i < ARRAY_SIZE(ctrls); i++)
+ v4l2_ctrl_new_custom(&dev->ctrl_handler, &ctrls[i], NULL);
+
+ if (dev->ctrl_handler.error) {
+ ov5693_remove(client);
+ return dev->ctrl_handler.error;
+ }
+
+ dev->ctrl_handler.lock = &dev->input_lock;
+ dev->sd.ctrl_handler = &dev->ctrl_handler;
+ v4l2_ctrl_handler_setup(&dev->ctrl_handler);
+
+ ret = media_entity_init(&dev->sd.entity, 1, &dev->pad, 0);
+ if (ret)
+ ov5693_remove(client);
+
+ /* vcm initialization */
+ if (dev->vcm_driver && dev->vcm_driver->init)
+ ret = dev->vcm_driver->init(&dev->sd);
+ if (ret) {
+ dev_err(&client->dev, "vcm init failed.\n");
+ ov5693_remove(client);
+ }
+
+ return ret;
+out_free:
+ v4l2_device_unregister_subdev(&dev->sd);
+ devm_kfree(&client->dev, dev);
+ return ret;
+}
+
+MODULE_DEVICE_TABLE(i2c, ov5693_id);
+static struct i2c_driver ov5693_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = OV5693_NAME,
+ },
+ .probe = ov5693_probe,
+ .remove = ov5693_remove,
+ .id_table = ov5693_id,
+};
+
+module_i2c_driver(ov5693_driver);
+
+MODULE_DESCRIPTION("A low-level driver for OmniVision 5693 sensors");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/ov5693/ov5693.h b/drivers/staging/ov5693/ov5693.h
new file mode 100644
index 000000000000..79aef69666e8
--- /dev/null
+++ b/drivers/staging/ov5693/ov5693.h
@@ -0,0 +1,848 @@
+/*
+ * Support for OmniVision OV5693 5M HD camera sensor.
+ *
+ * Copyright (c) 2013 Intel Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#ifndef __OV5693_H__
+#define __OV5693_H__
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <media/media-entity.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <linux/v4l2-mediabus.h>
+
+#include <linux/atomisp_platform.h>
+#include "ad5823.h"
+
+#define OV5693_NAME "ov5693"
+
+/* Defines for register writes and register array processing */
+#define I2C_MSG_LENGTH 0x2
+
+#define OV5693_FOCAL_LENGTH_NUM 278 /*2.78mm*/
+#define OV5693_FOCAL_LENGTH_DEM 100
+#define OV5693_F_NUMBER_DEFAULT_NUM 26
+#define OV5693_F_NUMBER_DEM 10
+
+#define OV5693_MAX_FOCUS_POS 1023
+#define OV5693_MAX_FOCUS_POS 1023
+#define OV5693_MAX_FOCUS_NEG (-1023)
+
+#define LARGEST_ALLOWED_RATIO_MISMATCH 800
+#define RATIO_SHIFT_BITS 13
+
+/*
+ * focal length bits definition:
+ * bits 31-16: numerator, bits 15-0: denominator
+ */
+#define OV5693_FOCAL_LENGTH_DEFAULT 0x1160064
+
+/*
+ * current f-number bits definition:
+ * bits 31-16: numerator, bits 15-0: denominator
+ */
+#define OV5693_F_NUMBER_DEFAULT 0x1a000a
+
+/*
+ * f-number range bits definition:
+ * bits 31-24: max f-number numerator
+ * bits 23-16: max f-number denominator
+ * bits 15-8: min f-number numerator
+ * bits 7-0: min f-number denominator
+ */
+#define OV5693_F_NUMBER_RANGE 0x1a0a1a0a
+#define OV5693_ID 0x5690
+
+#define OV5693_FINE_INTG_TIME_MIN 0
+#define OV5693_FINE_INTG_TIME_MAX_MARGIN 0
+#define OV5693_COARSE_INTG_TIME_MIN 1
+#define OV5693_COARSE_INTG_TIME_MAX_MARGIN (0xffff - 6)
+#define OV5693_INTEGRATION_TIME_MARGIN 8
+
+#define OV5693_BIN_FACTOR_MAX 2
+
+/*
+ * OV5693 System control registers
+ */
+#define OV5693_SW_RESET 0x0103
+#define OV5693_SW_STREAM 0x0100
+
+#define OV5693_SC_CMMN_CHIP_ID 0x300a
+#define OV5693_SC_CMMN_SUB_ID 0x302a /* process, version*/
+
+#define OV5693_AEC_PK_EXPO_H 0x3500
+#define OV5693_AEC_PK_EXPO_M 0x3501
+#define OV5693_AEC_PK_EXPO_L 0x3502
+#define OV5693_AGC_ADJ_H 0x350a
+#define OV5693_VTS_H 0x380e
+#define OV5693_GROUP_ACCESS 0x3208
+
+#define OV5693_MWB_GAIN_R_H 0x3400
+#define OV5693_MWB_GAIN_G_H 0x3402
+#define OV5693_MWB_GAIN_B_H 0x3404
+
+#define OV5693_H_CROP_START_H 0x3800
+#define OV5693_V_CROP_START_H 0x3802
+#define OV5693_H_CROP_END_H 0x3804
+#define OV5693_V_CROP_END_H 0x3806
+#define OV5693_H_OUTSIZE_H 0x3808
+#define OV5693_V_OUTSIZE_H 0x380a
+
+#define OV5693_START_STREAMING 0x01
+#define OV5693_STOP_STREAMING 0x00
+
+struct ov5693_vcm {
+ int (*power_up)(struct v4l2_subdev *sd);
+ int (*power_down)(struct v4l2_subdev *sd);
+ int (*init)(struct v4l2_subdev *sd);
+ int (*t_focus_vcm)(struct v4l2_subdev *sd, u16 val);
+ int (*t_focus_abs)(struct v4l2_subdev *sd, s32 value);
+ int (*t_focus_rel)(struct v4l2_subdev *sd, s32 value);
+ int (*q_focus_status)(struct v4l2_subdev *sd, s32 *value);
+ int (*q_focus_abs)(struct v4l2_subdev *sd, s32 *value);
+};
+
+struct ov5693_resolution {
+ u8 *desc;
+ const struct ov5693_reg *regs;
+ int res;
+ int width;
+ int height;
+ int fps;
+ int pix_clk_freq;
+ u16 skip_frames;
+ u16 pixels_per_line;
+ u16 lines_per_frame;
+ u8 bin_factor_x;
+ u8 bin_factor_y;
+ u8 bin_mode;
+ bool used;
+};
+
+struct ov5693_control {
+ struct v4l2_queryctrl qc;
+ int (*query)(struct v4l2_subdev *sd, s32 *value);
+ int (*tweak)(struct v4l2_subdev *sd, s32 value);
+};
+
+/*
+ * ov5693 device structure.
+ */
+struct ov5693_device {
+ struct v4l2_subdev sd;
+ struct media_pad pad;
+ struct v4l2_mbus_framefmt format;
+ struct mutex input_lock;
+
+ struct camera_sensor_platform_data *platform_data;
+ struct ov5693_vcm *vcm_driver;
+ int fmt_idx;
+ u8 res;
+ u8 type;
+
+ struct ov5693_resolution *ov5693_res;
+ int curr_res_num;
+
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct v4l2_ctrl *run_mode;
+};
+
+enum ov5693_tok_type {
+ OV5693_8BIT = 0x0001,
+ OV5693_16BIT = 0x0002,
+ OV5693_32BIT = 0x0004,
+ OV5693_TOK_TERM = 0xf000, /* terminating token for reg list */
+ OV5693_TOK_DELAY = 0xfe00, /* delay token for reg list */
+ OV5693_TOK_MASK = 0xfff0
+};
+
+/**
+ * struct ov5693_reg - MI sensor register format
+ * @type: type of the register
+ * @reg: 16-bit offset to register
+ * @val: 8/16/32-bit register value
+ *
+ * Define a structure for sensor register initialization values
+ */
+struct ov5693_reg {
+ enum ov5693_tok_type type;
+ u16 reg;
+ u32 val; /* @set value for read/mod/write, @mask */
+};
+
+#define to_ov5693_sensor(x) container_of(x, struct ov5693_device, sd)
+
+#define OV5693_MAX_WRITE_BUF_SIZE 30
+
+struct ov5693_write_buffer {
+ u16 addr;
+ u8 data[OV5693_MAX_WRITE_BUF_SIZE];
+};
+
+struct ov5693_write_ctrl {
+ int index;
+ struct ov5693_write_buffer buffer;
+};
+
+static const struct i2c_device_id ov5693_id[] = {
+ {OV5693_NAME, 0},
+ {}
+};
+
+/* ov5693 sensor initialization setting */
+static struct ov5693_reg const ov5693_init_setting[] = {
+ {OV5693_8BIT, 0x0103, 0x01},
+ {OV5693_8BIT, 0x3001, 0x0a},
+ {OV5693_8BIT, 0x3002, 0x80},
+ {OV5693_8BIT, 0x3006, 0x00},
+ {OV5693_8BIT, 0x3011, 0x21},
+ {OV5693_8BIT, 0x3012, 0x09},
+ {OV5693_8BIT, 0x3013, 0x10},
+ {OV5693_8BIT, 0x3014, 0x00},
+ {OV5693_8BIT, 0x3015, 0x08},
+ {OV5693_8BIT, 0x3016, 0xf0},
+ {OV5693_8BIT, 0x3017, 0xf0},
+ {OV5693_8BIT, 0x3018, 0xf0},
+ {OV5693_8BIT, 0x301b, 0xb4},
+ {OV5693_8BIT, 0x301d, 0x02},
+ {OV5693_8BIT, 0x3021, 0x00},
+ {OV5693_8BIT, 0x3022, 0x01},
+ {OV5693_8BIT, 0x3028, 0x44},
+ {OV5693_8BIT, 0x3098, 0x02},
+ {OV5693_8BIT, 0x3099, 0x19},
+ {OV5693_8BIT, 0x309a, 0x02},
+ {OV5693_8BIT, 0x309b, 0x01},
+ {OV5693_8BIT, 0x309c, 0x00},
+ {OV5693_8BIT, 0x30a0, 0xd2},
+ {OV5693_8BIT, 0x30a2, 0x01},
+ {OV5693_8BIT, 0x30b2, 0x00},
+ {OV5693_8BIT, 0x30b3, 0x7d},
+ {OV5693_8BIT, 0x30b4, 0x03},
+ {OV5693_8BIT, 0x30b5, 0x04},
+ {OV5693_8BIT, 0x30b6, 0x01},
+ {OV5693_8BIT, 0x3104, 0x21},
+ {OV5693_8BIT, 0x3106, 0x00},
+
+ /* Manual white balance */
+ {OV5693_8BIT, 0x3400, 0x04},
+ {OV5693_8BIT, 0x3401, 0x00},
+ {OV5693_8BIT, 0x3402, 0x04},
+ {OV5693_8BIT, 0x3403, 0x00},
+ {OV5693_8BIT, 0x3404, 0x04},
+ {OV5693_8BIT, 0x3405, 0x00},
+ {OV5693_8BIT, 0x3406, 0x01},
+
+ /* Manual exposure control */
+ {OV5693_8BIT, 0x3500, 0x00},
+ {OV5693_8BIT, 0x3503, 0x07},
+ {OV5693_8BIT, 0x3504, 0x00},
+ {OV5693_8BIT, 0x3505, 0x00},
+ {OV5693_8BIT, 0x3506, 0x00},
+ {OV5693_8BIT, 0x3507, 0x02},
+ {OV5693_8BIT, 0x3508, 0x00},
+
+ /* Manual gain control */
+ {OV5693_8BIT, 0x3509, 0x10},
+ {OV5693_8BIT, 0x350a, 0x00},
+ {OV5693_8BIT, 0x350b, 0x40},
+
+ {OV5693_8BIT, 0x3601, 0x0a},
+ {OV5693_8BIT, 0x3602, 0x38},
+ {OV5693_8BIT, 0x3612, 0x80},
+ {OV5693_8BIT, 0x3620, 0x54},
+ {OV5693_8BIT, 0x3621, 0xc7},
+ {OV5693_8BIT, 0x3622, 0x0f},
+ {OV5693_8BIT, 0x3625, 0x10},
+ {OV5693_8BIT, 0x3630, 0x55},
+ {OV5693_8BIT, 0x3631, 0xf4},
+ {OV5693_8BIT, 0x3632, 0x00},
+ {OV5693_8BIT, 0x3633, 0x34},
+ {OV5693_8BIT, 0x3634, 0x02},
+ {OV5693_8BIT, 0x364d, 0x0d},
+ {OV5693_8BIT, 0x364f, 0xdd},
+ {OV5693_8BIT, 0x3660, 0x04},
+ {OV5693_8BIT, 0x3662, 0x10},
+ {OV5693_8BIT, 0x3663, 0xf1},
+ {OV5693_8BIT, 0x3665, 0x00},
+ {OV5693_8BIT, 0x3666, 0x20},
+ {OV5693_8BIT, 0x3667, 0x00},
+ {OV5693_8BIT, 0x366a, 0x80},
+ {OV5693_8BIT, 0x3680, 0xe0},
+ {OV5693_8BIT, 0x3681, 0x00},
+ {OV5693_8BIT, 0x3700, 0x42},
+ {OV5693_8BIT, 0x3701, 0x14},
+ {OV5693_8BIT, 0x3702, 0xa0},
+ {OV5693_8BIT, 0x3703, 0xd8},
+ {OV5693_8BIT, 0x3704, 0x78},
+ {OV5693_8BIT, 0x3705, 0x02},
+ {OV5693_8BIT, 0x370a, 0x00},
+ {OV5693_8BIT, 0x370b, 0x20},
+ {OV5693_8BIT, 0x370c, 0x0c},
+ {OV5693_8BIT, 0x370d, 0x11},
+ {OV5693_8BIT, 0x370e, 0x00},
+ {OV5693_8BIT, 0x370f, 0x40},
+ {OV5693_8BIT, 0x3710, 0x00},
+ {OV5693_8BIT, 0x371a, 0x1c},
+ {OV5693_8BIT, 0x371b, 0x05},
+ {OV5693_8BIT, 0x371c, 0x01},
+ {OV5693_8BIT, 0x371e, 0xa1},
+ {OV5693_8BIT, 0x371f, 0x0c},
+ {OV5693_8BIT, 0x3721, 0x00},
+ {OV5693_8BIT, 0x3724, 0x10},
+ {OV5693_8BIT, 0x3726, 0x00},
+ {OV5693_8BIT, 0x372a, 0x01},
+ {OV5693_8BIT, 0x3730, 0x10},
+ {OV5693_8BIT, 0x3738, 0x22},
+ {OV5693_8BIT, 0x3739, 0xe5},
+ {OV5693_8BIT, 0x373a, 0x50},
+ {OV5693_8BIT, 0x373b, 0x02},
+ {OV5693_8BIT, 0x373c, 0x41},
+ {OV5693_8BIT, 0x373f, 0x02},
+ {OV5693_8BIT, 0x3740, 0x42},
+ {OV5693_8BIT, 0x3741, 0x02},
+ {OV5693_8BIT, 0x3742, 0x18},
+ {OV5693_8BIT, 0x3743, 0x01},
+ {OV5693_8BIT, 0x3744, 0x02},
+ {OV5693_8BIT, 0x3747, 0x10},
+ {OV5693_8BIT, 0x374c, 0x04},
+ {OV5693_8BIT, 0x3751, 0xf0},
+ {OV5693_8BIT, 0x3752, 0x00},
+ {OV5693_8BIT, 0x3753, 0x00},
+ {OV5693_8BIT, 0x3754, 0xc0},
+ {OV5693_8BIT, 0x3755, 0x00},
+ {OV5693_8BIT, 0x3756, 0x1a},
+ {OV5693_8BIT, 0x3758, 0x00},
+ {OV5693_8BIT, 0x3759, 0x0f},
+ {OV5693_8BIT, 0x376b, 0x44},
+ {OV5693_8BIT, 0x375c, 0x04},
+ {OV5693_8BIT, 0x3774, 0x10},
+ {OV5693_8BIT, 0x3776, 0x00},
+ {OV5693_8BIT, 0x377f, 0x08},
+ {OV5693_8BIT, 0x3780, 0x22},
+ {OV5693_8BIT, 0x3781, 0x0c},
+ {OV5693_8BIT, 0x3784, 0x2c},
+ {OV5693_8BIT, 0x3785, 0x1e},
+ {OV5693_8BIT, 0x378f, 0xf5},
+ {OV5693_8BIT, 0x3791, 0xb0},
+ {OV5693_8BIT, 0x3795, 0x00},
+ {OV5693_8BIT, 0x3796, 0x64},
+ {OV5693_8BIT, 0x3797, 0x11},
+ {OV5693_8BIT, 0x3798, 0x30},
+ {OV5693_8BIT, 0x3799, 0x41},
+ {OV5693_8BIT, 0x379a, 0x07},
+ {OV5693_8BIT, 0x379b, 0xb0},
+ {OV5693_8BIT, 0x379c, 0x0c},
+ {OV5693_8BIT, 0x37c5, 0x00},
+ {OV5693_8BIT, 0x37c6, 0x00},
+ {OV5693_8BIT, 0x37c7, 0x00},
+ {OV5693_8BIT, 0x37c9, 0x00},
+ {OV5693_8BIT, 0x37ca, 0x00},
+ {OV5693_8BIT, 0x37cb, 0x00},
+ {OV5693_8BIT, 0x37de, 0x00},
+ {OV5693_8BIT, 0x37df, 0x00},
+ {OV5693_8BIT, 0x3800, 0x00},
+ {OV5693_8BIT, 0x3801, 0x00},
+ {OV5693_8BIT, 0x3802, 0x00},
+ {OV5693_8BIT, 0x3804, 0x0a},
+ {OV5693_8BIT, 0x3805, 0x3f},
+ {OV5693_8BIT, 0x3810, 0x00},
+ {OV5693_8BIT, 0x3812, 0x00},
+ {OV5693_8BIT, 0x3823, 0x00},
+ {OV5693_8BIT, 0x3824, 0x00},
+ {OV5693_8BIT, 0x3825, 0x00},
+ {OV5693_8BIT, 0x3826, 0x00},
+ {OV5693_8BIT, 0x3827, 0x00},
+ {OV5693_8BIT, 0x382a, 0x04},
+ {OV5693_8BIT, 0x3a04, 0x06},
+ {OV5693_8BIT, 0x3a05, 0x14},
+ {OV5693_8BIT, 0x3a06, 0x00},
+ {OV5693_8BIT, 0x3a07, 0xfe},
+ {OV5693_8BIT, 0x3b00, 0x00},
+ {OV5693_8BIT, 0x3b02, 0x00},
+ {OV5693_8BIT, 0x3b03, 0x00},
+ {OV5693_8BIT, 0x3b04, 0x00},
+ {OV5693_8BIT, 0x3b05, 0x00},
+ {OV5693_8BIT, 0x3e07, 0x20},
+ {OV5693_8BIT, 0x4000, 0x08},
+ {OV5693_8BIT, 0x4001, 0x04},
+ {OV5693_8BIT, 0x4002, 0x45},
+ {OV5693_8BIT, 0x4004, 0x08},
+ {OV5693_8BIT, 0x4005, 0x18},
+ {OV5693_8BIT, 0x4006, 0x20},
+ {OV5693_8BIT, 0x4008, 0x24},
+ {OV5693_8BIT, 0x4009, 0x10},
+ {OV5693_8BIT, 0x400c, 0x00},
+ {OV5693_8BIT, 0x400d, 0x00},
+ {OV5693_8BIT, 0x4058, 0x00},
+ {OV5693_8BIT, 0x404e, 0x37},
+ {OV5693_8BIT, 0x404f, 0x8f},
+ {OV5693_8BIT, 0x4058, 0x00},
+ {OV5693_8BIT, 0x4101, 0xb2},
+ {OV5693_8BIT, 0x4303, 0x00},
+ {OV5693_8BIT, 0x4304, 0x08},
+ {OV5693_8BIT, 0x4307, 0x30},
+ {OV5693_8BIT, 0x4311, 0x04},
+ {OV5693_8BIT, 0x4315, 0x01},
+ {OV5693_8BIT, 0x4511, 0x05},
+ {OV5693_8BIT, 0x4512, 0x01},
+ {OV5693_8BIT, 0x4806, 0x00},
+ {OV5693_8BIT, 0x4816, 0x52},
+ {OV5693_8BIT, 0x481f, 0x30},
+ {OV5693_8BIT, 0x4826, 0x2c},
+ {OV5693_8BIT, 0x4831, 0x64},
+ {OV5693_8BIT, 0x4d00, 0x04},
+ {OV5693_8BIT, 0x4d01, 0x71},
+ {OV5693_8BIT, 0x4d02, 0xfd},
+ {OV5693_8BIT, 0x4d03, 0xf5},
+ {OV5693_8BIT, 0x4d04, 0x0c},
+ {OV5693_8BIT, 0x4d05, 0xcc},
+ {OV5693_8BIT, 0x4837, 0x0a},
+ {OV5693_8BIT, 0x5000, 0x06},
+ {OV5693_8BIT, 0x5001, 0x01},
+ {OV5693_8BIT, 0x5003, 0x20},
+ {OV5693_8BIT, 0x5046, 0x0a},
+ {OV5693_8BIT, 0x5013, 0x00},
+ {OV5693_8BIT, 0x5046, 0x0a},
+ {OV5693_8BIT, 0x5780, 0x1c},
+ {OV5693_8BIT, 0x5786, 0x20},
+ {OV5693_8BIT, 0x5787, 0x10},
+ {OV5693_8BIT, 0x5788, 0x18},
+ {OV5693_8BIT, 0x578a, 0x04},
+ {OV5693_8BIT, 0x578b, 0x02},
+ {OV5693_8BIT, 0x578c, 0x02},
+ {OV5693_8BIT, 0x578e, 0x06},
+ {OV5693_8BIT, 0x578f, 0x02},
+ {OV5693_8BIT, 0x5790, 0x02},
+ {OV5693_8BIT, 0x5791, 0xff},
+ {OV5693_8BIT, 0x5842, 0x01},
+ {OV5693_8BIT, 0x5843, 0x2b},
+ {OV5693_8BIT, 0x5844, 0x01},
+ {OV5693_8BIT, 0x5845, 0x92},
+ {OV5693_8BIT, 0x5846, 0x01},
+ {OV5693_8BIT, 0x5847, 0x8f},
+ {OV5693_8BIT, 0x5848, 0x01},
+ {OV5693_8BIT, 0x5849, 0x0c},
+ {OV5693_8BIT, 0x5e00, 0x00},
+ {OV5693_8BIT, 0x5e10, 0x0c},
+ {OV5693_8BIT, 0x0100, 0x00},
+ {OV5693_TOK_TERM, 0, 0}
+};
+
+/*
+ * Register settings for various resolution
+ */
+
+/*
+------------------------------------
+@@ FULL QSXGA (2592x1944) 15fps 33.33ms VBlank 2lane 10Bit
+100 99 2592 1944
+100 98 1 0
+102 3601 bb8 ;Pather tool use only
+c8 1 f2 ; New FPGA Board
+c8 20 22 ; New FPGA Board
+c8 10 42 ; MIPI DFGA CYCY3 Board use only
+;
+c8 f 32 ; input clock to 19.2MHz
+;
+; OV5690 setting version History
+;
+;
+; V18b
+*/
+static struct ov5693_reg const ov5693_5M_15fps[] = {
+ {OV5693_8BIT, 0x3501, 0x7b},
+ {OV5693_8BIT, 0x3502, 0x00},
+ {OV5693_8BIT, 0x3708, 0xe2},
+ {OV5693_8BIT, 0x3709, 0xc3},
+ {OV5693_8BIT, 0x3800, 0x00}, /* x_addr_start: 0 */
+ {OV5693_8BIT, 0x3801, 0x00},
+ {OV5693_8BIT, 0x3802, 0x00}, /* y_addr_start: 0 */
+ {OV5693_8BIT, 0x3803, 0x00},
+ {OV5693_8BIT, 0x3804, 0x0a}, /* x_addr_end: 2623 */
+ {OV5693_8BIT, 0x3805, 0x3f},
+ {OV5693_8BIT, 0x3806, 0x07}, /* y_addr_end: 1955 */
+ {OV5693_8BIT, 0x3807, 0xa3},
+ {OV5693_8BIT, 0x3808, 0x0a}, /* x output size: 2592 */
+ {OV5693_8BIT, 0x3809, 0x20},
+ {OV5693_8BIT, 0x380a, 0x07}, /* y output size: 1944 */
+ {OV5693_8BIT, 0x380b, 0x98},
+ {OV5693_8BIT, 0x380c, 0x0e}, /* total x output size: 3688 */
+ {OV5693_8BIT, 0x380d, 0x68},
+ {OV5693_8BIT, 0x380e, 0x0f}, /* total y output size: 3968 */
+ {OV5693_8BIT, 0x380f, 0x80},
+ {OV5693_8BIT, 0x3810, 0x00}, /* x offset: 16 */
+ {OV5693_8BIT, 0x3811, 0x10},
+ {OV5693_8BIT, 0x3812, 0x00}, /* y offset: 6 */
+ {OV5693_8BIT, 0x3813, 0x06},
+ {OV5693_8BIT, 0x3814, 0x11},
+ {OV5693_8BIT, 0x3815, 0x11},
+ {OV5693_8BIT, 0x3820, 0x00},
+ {OV5693_8BIT, 0x3821, 0x1e},
+ {OV5693_8BIT, 0x5002, 0x00},
+ {OV5693_TOK_TERM, 0, 0}
+};
+
+/*
+@@ OV5693 1940x1096 30fps 8.8ms VBlanking 2lane 10Bit(Scaling)
+100 99 1940 1096
+100 98 1 0
+102 3601 bb8 ;Pather tool use only
+102 40 0 ; HDR Mode off
+c8 1 f2 ; New FPGA Board
+c8 20 22 ; New FPGA Board
+c8 10 42 ; MIPI DFGA CYCY3 Board use only
+;
+c8 f 32 ; input clock to 19.2MHz
+;
+; OV5690 setting version History
+;
+;
+; V18b
+*/
+static struct ov5693_reg const ov5693_1080p_30fps[] = {
+ {OV5693_8BIT, 0x3501, 0x7b},
+ {OV5693_8BIT, 0x3502, 0x00},
+ {OV5693_8BIT, 0x3708, 0xe2},
+ {OV5693_8BIT, 0x3709, 0xc3},
+ {OV5693_8BIT, 0x3800, 0x00}, /* x_addr_start: 0 */
+ {OV5693_8BIT, 0x3801, 0x00},
+ {OV5693_8BIT, 0x3802, 0x00}, /* y_addr_start: 240 */
+ {OV5693_8BIT, 0x3803, 0xf0},
+ {OV5693_8BIT, 0x3804, 0x0a}, /* x_addr_end: 2591 */
+ {OV5693_8BIT, 0x3805, 0x1f},
+ {OV5693_8BIT, 0x3806, 0x06}, /* y_addr_end: 1703 */
+ {OV5693_8BIT, 0x3807, 0xa7},
+ {OV5693_8BIT, 0x3808, 0x07}, /* x output size: 1940 */
+ {OV5693_8BIT, 0x3809, 0x94},
+ {OV5693_8BIT, 0x380a, 0x04}, /* y output size: 1096 */
+ {OV5693_8BIT, 0x380b, 0x48},
+ {OV5693_8BIT, 0x380c, 0x0e}, /* total x output size: 3688 */
+ {OV5693_8BIT, 0x380d, 0x68},
+ {OV5693_8BIT, 0x380e, 0x0b}, /* total y output size: 2984 */
+ {OV5693_8BIT, 0x380f, 0xa8},
+ {OV5693_8BIT, 0x3810, 0x00}, /* x offset: 2 */
+ {OV5693_8BIT, 0x3811, 0x02},
+ {OV5693_8BIT, 0x3812, 0x00}, /* y offset: 2 */
+ {OV5693_8BIT, 0x3813, 0x02},
+ {OV5693_8BIT, 0x3814, 0x11},
+ {OV5693_8BIT, 0x3815, 0x11},
+ {OV5693_8BIT, 0x3820, 0x00},
+ {OV5693_8BIT, 0x3821, 0x1e},
+ {OV5693_8BIT, 0x5002, 0x80},
+ {OV5693_TOK_TERM, 0, 0}
+};
+
+/*
+ * 1296x736 30fps 8.8ms VBlanking 2lane 10Bit (Scaling)
+ */
+static struct ov5693_reg const ov5693_720p_30fps[] = {
+ {OV5693_8BIT, 0x3501, 0x3d},
+ {OV5693_8BIT, 0x3502, 0x00},
+ {OV5693_8BIT, 0x3708, 0xe6},
+ {OV5693_8BIT, 0x3709, 0xc7},
+ {OV5693_8BIT, 0x3800, 0x00}, /* x_addr_start: 0 */
+ {OV5693_8BIT, 0x3801, 0x00},
+ {OV5693_8BIT, 0x3802, 0x00}, /* y_addr_start: 0 */
+ {OV5693_8BIT, 0x3803, 0x00},
+ {OV5693_8BIT, 0x3804, 0x0a}, /* x_addr_end: 2623 */
+ {OV5693_8BIT, 0x3805, 0x3f},
+ {OV5693_8BIT, 0x3806, 0x07}, /* y_addr_end: 1955 */
+ {OV5693_8BIT, 0x3807, 0xa3},
+ {OV5693_8BIT, 0x3808, 0x05}, /* x output size: 1296 */
+ {OV5693_8BIT, 0x3809, 0x10},
+ {OV5693_8BIT, 0x380a, 0x02}, /* y output size: 736 */
+ {OV5693_8BIT, 0x380b, 0xe0},
+ {OV5693_8BIT, 0x380c, 0x0a}, /* total x output size: 2688 */
+ {OV5693_8BIT, 0x380d, 0x80},
+ {OV5693_8BIT, 0x380e, 0x07}, /* total y output size: 1984 */
+ {OV5693_8BIT, 0x380f, 0xc0},
+ {OV5693_8BIT, 0x3810, 0x00}, /* x offset: 8 */
+ {OV5693_8BIT, 0x3811, 0x08},
+ {OV5693_8BIT, 0x3812, 0x00}, /* y offset: 2 */
+ {OV5693_8BIT, 0x3813, 0x02},
+ {OV5693_8BIT, 0x3814, 0x31},
+ {OV5693_8BIT, 0x3815, 0x31},
+ {OV5693_8BIT, 0x3820, 0x04},
+ {OV5693_8BIT, 0x3821, 0x1f},
+ {OV5693_8BIT, 0x5002, 0x80},
+ {OV5693_TOK_TERM, 0, 0}
+};
+
+/*
+ * 736x496 30fps 8.8ms VBlanking 2lane 10Bit (Scaling)
+ */
+static struct ov5693_reg const ov5693_480p_30fps[] = {
+ {OV5693_8BIT, 0x3501, 0x3d},
+ {OV5693_8BIT, 0x3502, 0x00},
+ {OV5693_8BIT, 0x3708, 0xe6},
+ {OV5693_8BIT, 0x3709, 0xc7},
+ {OV5693_8BIT, 0x3800, 0x00}, /* x_addr_start: 0 */
+ {OV5693_8BIT, 0x3801, 0x00},
+ {OV5693_8BIT, 0x3802, 0x00}, /* y_addr_start: 7 */
+ {OV5693_8BIT, 0x3803, 0x07},
+ {OV5693_8BIT, 0x3804, 0x0a}, /* x_addr_end: 2623 */
+ {OV5693_8BIT, 0x3805, 0x3f},
+ {OV5693_8BIT, 0x3806, 0x07}, /* y_addr_end: 1955 */
+ {OV5693_8BIT, 0x3807, 0xa3},
+ {OV5693_8BIT, 0x3808, 0x02}, /* x output size: 736 */
+ {OV5693_8BIT, 0x3809, 0xe0},
+ {OV5693_8BIT, 0x380a, 0x01}, /* y output size: 496 */
+ {OV5693_8BIT, 0x380b, 0xf0},
+ {OV5693_8BIT, 0x380c, 0x0a}, /* total x output size: 2688 */
+ {OV5693_8BIT, 0x380d, 0x80},
+ {OV5693_8BIT, 0x380e, 0x07}, /* total y output size: 1984 */
+ {OV5693_8BIT, 0x380f, 0xc0},
+ {OV5693_8BIT, 0x3810, 0x00}, /* x offset: 8 */
+ {OV5693_8BIT, 0x3811, 0x08},
+ {OV5693_8BIT, 0x3812, 0x00}, /* y offset: 2 */
+ {OV5693_8BIT, 0x3813, 0x02},
+ {OV5693_8BIT, 0x3814, 0x31},
+ {OV5693_8BIT, 0x3815, 0x31},
+ {OV5693_8BIT, 0x3820, 0x04},
+ {OV5693_8BIT, 0x3821, 0x1f},
+ {OV5693_8BIT, 0x5002, 0x80},
+ {OV5693_TOK_TERM, 0, 0}
+};
+
+/*
+@@ OV5693 656x496 30fps 17ms VBlanking 2lane 10Bit(Scaling)
+100 99 656 496
+100 98 1 0
+102 3601 BB8 ;Pather tool use only
+c8 1 f2 ; New FPGA Board
+c8 20 22 ; New FPGA Board
+; OV5690 setting version History
+;
+c8 f 32 ; input clock to 19.2MHz
+;
+; V18b
+*/
+static struct ov5693_reg const ov5693_VGA_30fps[] = {
+ {OV5693_8BIT, 0x3501, 0x3d},
+ {OV5693_8BIT, 0x3502, 0x00},
+ {OV5693_8BIT, 0x3708, 0xe6},
+ {OV5693_8BIT, 0x3709, 0xc7},
+ {OV5693_8BIT, 0x3800, 0x00}, /* x_addr_start: 0 */
+ {OV5693_8BIT, 0x3801, 0x00},
+ {OV5693_8BIT, 0x3802, 0x00}, /* y_addr_start: 0 */
+ {OV5693_8BIT, 0x3803, 0x00},
+ {OV5693_8BIT, 0x3804, 0x0a}, /* x_addr_end: 2623 */
+ {OV5693_8BIT, 0x3805, 0x3f},
+ {OV5693_8BIT, 0x3806, 0x07}, /* y_addr_end: 1955 */
+ {OV5693_8BIT, 0x3807, 0xa3},
+ {OV5693_8BIT, 0x3808, 0x02}, /* x output size: 656 */
+ {OV5693_8BIT, 0x3809, 0x90},
+ {OV5693_8BIT, 0x380a, 0x01}, /* y output size: 496 */
+ {OV5693_8BIT, 0x380b, 0xf0},
+ {OV5693_8BIT, 0x380c, 0x0a}, /* total x output size: 2688 */
+ {OV5693_8BIT, 0x380d, 0x80},
+ {OV5693_8BIT, 0x380e, 0x07}, /* total y output size: 1984 */
+ {OV5693_8BIT, 0x380f, 0xc0},
+ {OV5693_8BIT, 0x3810, 0x00}, /* x offset: 13 */
+ {OV5693_8BIT, 0x3811, 0x0d},
+ {OV5693_8BIT, 0x3812, 0x00}, /* y offset: 3 */
+ {OV5693_8BIT, 0x3813, 0x03},
+ {OV5693_8BIT, 0x3814, 0x31},
+ {OV5693_8BIT, 0x3815, 0x31},
+ {OV5693_8BIT, 0x3820, 0x04},
+ {OV5693_8BIT, 0x3821, 0x1f},
+ {OV5693_8BIT, 0x5002, 0x80},
+ {OV5693_TOK_TERM, 0, 0}
+};
+
+struct ov5693_resolution ov5693_res_preview[] = {
+ {
+ .desc = "ov5693_VGA_30fps",
+ .width = 656,
+ .height = 496,
+ .fps = 30,
+ .pix_clk_freq = 81,
+ .used = 0,
+ .pixels_per_line = 2688,
+ .lines_per_frame = 1984,
+ .bin_factor_x = 2,
+ .bin_factor_y = 2,
+ .bin_mode = 0,
+ .skip_frames = 3,
+ .regs = ov5693_VGA_30fps,
+ },
+ {
+ .desc = "ov5693_1080P_30fps",
+ .width = 1940,
+ .height = 1096,
+ .fps = 30,
+ .pix_clk_freq = 81,
+ .used = 0,
+ .pixels_per_line = 3688,
+ .lines_per_frame = 2984,
+ .bin_factor_x = 0,
+ .bin_factor_y = 0,
+ .bin_mode = 0,
+ .skip_frames = 3,
+ .regs = ov5693_1080p_30fps,
+ },
+ {
+ .desc = "ov5693_5M_15fps",
+ .width = 2592,
+ .height = 1944,
+ .fps = 15,
+ .pix_clk_freq = 81,
+ .used = 0,
+ .pixels_per_line = 3688,
+ .lines_per_frame = 3968,
+ .bin_factor_x = 0,
+ .bin_factor_y = 0,
+ .bin_mode = 0,
+ .skip_frames = 3,
+ .regs = ov5693_5M_15fps,
+ },
+};
+#define N_RES_PREVIEW (ARRAY_SIZE(ov5693_res_preview))
+
+struct ov5693_resolution ov5693_res_still[] = {
+ {
+ .desc = "ov5693_VGA_30fps",
+ .width = 656,
+ .height = 496,
+ .fps = 30,
+ .pix_clk_freq = 81,
+ .used = 0,
+ .pixels_per_line = 2688,
+ .lines_per_frame = 1984,
+ .bin_factor_x = 2,
+ .bin_factor_y = 2,
+ .bin_mode = 0,
+ .skip_frames = 3,
+ .regs = ov5693_VGA_30fps,
+ },
+ {
+ .desc = "ov5693_1080P_30fps",
+ .width = 1940,
+ .height = 1096,
+ .fps = 30,
+ .pix_clk_freq = 81,
+ .used = 0,
+ .pixels_per_line = 3688,
+ .lines_per_frame = 2984,
+ .bin_factor_x = 0,
+ .bin_factor_y = 0,
+ .bin_mode = 0,
+ .skip_frames = 3,
+ .regs = ov5693_1080p_30fps,
+ },
+ {
+ .desc = "ov5693_5M_15fps",
+ .width = 2592,
+ .height = 1944,
+ .fps = 15,
+ .pix_clk_freq = 81,
+ .used = 0,
+ .pixels_per_line = 3688,
+ .lines_per_frame = 3968,
+ .bin_factor_x = 0,
+ .bin_factor_y = 0,
+ .bin_mode = 0,
+ .skip_frames = 3,
+ .regs = ov5693_5M_15fps,
+ },
+};
+#define N_RES_STILL (ARRAY_SIZE(ov5693_res_still))
+
+struct ov5693_resolution ov5693_res_video[] = {
+ {
+ .desc = "ov5693_VGA_30fps",
+ .width = 656,
+ .height = 496,
+ .fps = 30,
+ .pix_clk_freq = 81,
+ .used = 0,
+ .pixels_per_line = 2688,
+ .lines_per_frame = 1984,
+ .bin_factor_x = 2,
+ .bin_factor_y = 2,
+ .bin_mode = 0,
+ .skip_frames = 3,
+ .regs = ov5693_VGA_30fps,
+ },
+ {
+ .desc = "ov5693_480P_30fps",
+ .width = 736,
+ .height = 496,
+ .fps = 30,
+ .pix_clk_freq = 81,
+ .used = 0,
+ .pixels_per_line = 2688,
+ .lines_per_frame = 1984,
+ .bin_factor_x = 2,
+ .bin_factor_y = 2,
+ .bin_mode = 0,
+ .skip_frames = 1,
+ .regs = ov5693_480p_30fps,
+ },
+ {
+ .desc = "ov5693_720p_30fps",
+ .width = 1296,
+ .height = 736,
+ .fps = 30,
+ .pix_clk_freq = 81,
+ .used = 0,
+ .pixels_per_line = 2688,
+ .lines_per_frame = 1984,
+ .bin_factor_x = 2,
+ .bin_factor_y = 2,
+ .bin_mode = 0,
+ .skip_frames = 1,
+ .regs = ov5693_720p_30fps,
+ },
+ {
+ .desc = "ov5693_1080P_30fps",
+ .width = 1940,
+ .height = 1096,
+ .fps = 30,
+ .pix_clk_freq = 81,
+ .used = 0,
+ .pixels_per_line = 3688,
+ .lines_per_frame = 2984,
+ .bin_factor_x = 0,
+ .bin_factor_y = 0,
+ .bin_mode = 0,
+ .skip_frames = 3,
+ .regs = ov5693_1080p_30fps,
+ },
+};
+#define N_RES_VIDEO (ARRAY_SIZE(ov5693_res_video))
+
+struct ov5693_vcm ov5693_vcm_ops = {
+ .power_up = ad5823_vcm_power_up,
+ .power_down = ad5823_vcm_power_down,
+ .init = ad5823_vcm_init,
+ .t_focus_vcm = ad5823_t_focus_vcm,
+ .t_focus_abs = ad5823_t_focus_abs,
+ .t_focus_rel = ad5823_t_focus_rel,
+ .q_focus_status = ad5823_q_focus_status,
+ .q_focus_abs = ad5823_q_focus_abs,
+};
+#endif
--
2.17.1