2754 lines
72 KiB
Diff
2754 lines
72 KiB
Diff
From 4f79924d2848c13e9a0830c0c575421768f8d58a Mon Sep 17 00:00:00 2001
|
|
From: Maximilian Luz <luzmaximilian@gmail.com>
|
|
Date: Tue, 2 Jul 2019 23:50:29 +0200
|
|
Subject: [PATCH 04/12] 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 c3ddbf6c202a..15143bbef860 100644
|
|
--- a/drivers/media/usb/uvc/uvc_driver.c
|
|
+++ b/drivers/media/usb/uvc/uvc_driver.c
|
|
@@ -2365,6 +2365,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, ®_val);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ buf->crop_horizontal_start = reg_val;
|
|
+
|
|
+ ret = ov5693_read_reg(client, OV5693_16BIT,
|
|
+ OV5693_V_CROP_START_H, ®_val);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ buf->crop_vertical_start = reg_val;
|
|
+
|
|
+ ret = ov5693_read_reg(client, OV5693_16BIT,
|
|
+ OV5693_H_CROP_END_H, ®_val);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ buf->crop_horizontal_end = reg_val;
|
|
+
|
|
+ ret = ov5693_read_reg(client, OV5693_16BIT,
|
|
+ OV5693_V_CROP_END_H, ®_val);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ buf->crop_vertical_end = reg_val;
|
|
+
|
|
+ ret = ov5693_read_reg(client, OV5693_16BIT,
|
|
+ OV5693_H_OUTSIZE_H, ®_val);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ buf->output_width = reg_val;
|
|
+
|
|
+ ret = ov5693_read_reg(client, OV5693_16BIT,
|
|
+ OV5693_V_OUTSIZE_H, ®_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,
|
|
+ ®_v);
|
|
+ if (ret)
|
|
+ goto err;
|
|
+
|
|
+ ret = ov5693_read_reg(client, OV5693_8BIT,
|
|
+ OV5693_AEC_PK_EXPO_M,
|
|
+ ®_v2);
|
|
+ if (ret)
|
|
+ goto err;
|
|
+
|
|
+ reg_v += reg_v2 << 8;
|
|
+ ret = ov5693_read_reg(client, OV5693_8BIT,
|
|
+ OV5693_AEC_PK_EXPO_H,
|
|
+ ®_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.22.0
|
|
|