depends on SOC_CAMERA && I2C
help
This is a tw9910 video driver
+
+source "drivers/media/i2c/soc_camera/rockchip/Kconfig"
\ No newline at end of file
obj-$(CONFIG_SOC_CAMERA_OV9740) += ov9740.o
obj-$(CONFIG_SOC_CAMERA_RJ54N1) += rj54n1cb0c.o
obj-$(CONFIG_SOC_CAMERA_TW9910) += tw9910.o
+obj-y += rockchip/
--- /dev/null
+config VIDEO_ov8858
+ tristate "ov8858 driver adapt to rockchip cif isp platform"
+ depends on VIDEO_V4L2 && VIDEO_RK_CIF_ISP10 && I2C
+ default n
+ ---help---
+ This is ov8858 camera driver adapt to rockchip cif isp platform.
+
+config VIDEO_ov2710
+ tristate "ov2710 driver adapt to rockchip cif isp platform"
+ depends on VIDEO_V4L2 && VIDEO_RK_CIF_ISP10 && I2C
+ default n
+ ---help---
+ This is ov2710 camera driver adapt to rockchip cif isp platform.
+
+config VIDEO_ov4689
+ tristate "ov4689 driver adapt to rockchip cif isp platform"
+ depends on VIDEO_V4L2 && VIDEO_RK_CIF_ISP10 && I2C
+ default n
+ ---help---
+ This is ov8858 camera driver adapt to rockchip cif isp platform.
+
+config VIDEO_imx323
+ tristate "imx323 driver adapt to rockchip cif isp platform"
+ depends on VIDEO_V4L2 && VIDEO_RK_CIF_ISP10 && I2C
+ default n
+ ---help---
+ This is imx323 camera driver adapt to rockchip cif isp platform.
--- /dev/null
+obj-$(CONFIG_VIDEO_ov8858) += ov_camera_module.o rk_camera_module.o ov8858_v4l2-i2c-subdev.o
+obj-$(CONFIG_VIDEO_ov2710) += ov_camera_module.o rk_camera_module.o ov2710_v4l2-i2c-subdev.o
+obj-$(CONFIG_VIDEO_ov4689) += ov_camera_module.o rk_camera_module.o ov4689_v4l2-i2c-subdev.o
+obj-$(CONFIG_VIDEO_imx323) += imx_camera_module.o rk_camera_module.o imx323_v4l2-i2c-subdev.o
--- /dev/null
+/*
+ * aptina_camera_module.c
+ *
+ * Generic galaxycore sensor driver
+ *
+ * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd.
+ *
+ * Copyright (C) 2012-2014 Intel Mobile Communications GmbH
+ *
+ * Copyright (C) 2008 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+
+#include <linux/delay.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-device.h>
+#include <media/videobuf-core.h>
+#include <linux/slab.h>
+#include <linux/gcd.h>
+#include <linux/i2c.h>
+#include <media/v4l2-controls_rockchip.h>
+#include "aptina_camera_module.h"
+
+#define I2C_M_WR 0
+#define I2C_MSG_MAX 300
+#define I2C_DATA_MAX (I2C_MSG_MAX * 3)
+
+/* ======================================================================== */
+
+struct aptina_camera_module *to_aptina_camera_module(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct aptina_camera_module, sd);
+}
+
+/* ======================================================================== */
+
+void aptina_camera_module_reset(
+ struct aptina_camera_module *cam_mod)
+{
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "\n");
+
+ cam_mod->inited = false;
+ cam_mod->active_config = NULL;
+ cam_mod->update_config = true;
+ cam_mod->frm_fmt_valid = false;
+ cam_mod->frm_intrvl_valid = false;
+ cam_mod->exp_config.auto_exp = false;
+ cam_mod->exp_config.auto_gain = false;
+ cam_mod->wb_config.auto_wb = false;
+ cam_mod->hflip = false;
+ cam_mod->vflip = false;
+ cam_mod->auto_adjust_fps = true;
+ cam_mod->rotation = 0;
+ cam_mod->ctrl_updt = 0;
+ cam_mod->state = APTINA_CAMERA_MODULE_POWER_OFF;
+ cam_mod->state_before_suspend = APTINA_CAMERA_MODULE_POWER_OFF;
+}
+
+/* ======================================================================== */
+
+int aptina_read_i2c_reg(
+ struct v4l2_subdev *sd,
+ u16 data_length,
+ u16 reg,
+ u32 *val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret = 0;
+ struct i2c_msg msg[1];
+ unsigned char data[2] = { 0, 0};
+
+ if (!client->adapter) {
+ pltfrm_camera_module_pr_err(sd, "client->adapter NULL\n");
+ return -ENODEV;
+ }
+
+ msg->addr = client->addr;
+ msg->flags = I2C_M_WR;
+ msg->len = 2;
+ msg->buf = data;
+
+ /* High byte goes out first */
+ data[0] = (u8)((reg >> 8) & 0xff);
+ data[1] = (u8)(reg & 0xff);
+
+ ret = i2c_transfer(client->adapter, msg, 1);
+ if (ret >= 0) {
+ mdelay(3);
+ msg->flags = I2C_M_RD;
+ msg->len = data_length;
+ i2c_transfer(client->adapter, msg, 1);
+ }
+ if (ret >= 0) {
+ *val = 0;
+ /* High byte comes first */
+ if (data_length == 1)
+ *val = data[0];
+ else if (data_length == 2)
+ *val = data[1] + (data[0] << 8);
+ else
+ ;
+
+ return 0;
+ }
+ pltfrm_camera_module_pr_err(sd,
+ "i2c read from offset 0x%08x failed with error %d\n", reg, ret);
+ return ret;
+}
+
+/* ======================================================================== */
+
+int aptina_write_i2c_reg(
+ struct v4l2_subdev *sd,
+ u16 reg, u16 val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret = 0;
+ struct i2c_msg msg[1];
+ unsigned char data[4] = {0, 0, 0, 0};
+ int retries;
+
+ if (!client->adapter) {
+ pltfrm_camera_module_pr_err(sd, "client->adapter NULL\n");
+ return -ENODEV;
+ }
+
+ for (retries = 0; retries < 5; retries++) {
+ msg->addr = client->addr;
+ msg->flags = I2C_M_WR;
+ msg->len = 4;
+ msg->buf = data;
+
+ /* high byte goes out first */
+ data[0] = (u8)((reg >> 8) & 0xff);
+ data[1] = (u8)(reg & 0xff);
+ data[2] = (u8)((val >> 8) & 0xff);
+ data[3] = (u8)(val & 0xff);
+
+ ret = i2c_transfer(client->adapter, msg, 1);
+ usleep_range(20, 50);
+
+ if (ret == 1)
+ return 0;
+
+ pltfrm_camera_module_pr_debug(sd,
+ "retrying I2C... %d\n", retries);
+ retries++;
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(msecs_to_jiffies(20));
+ }
+
+ pltfrm_camera_module_pr_err(sd,
+ "i2c write to offset 0x%08x failed with error %d\n", reg, ret);
+ return ret;
+}
+
+/* ======================================================================== */
+
+int aptina_write_reglist(
+ struct v4l2_subdev *sd,
+ const struct pltfrm_camera_module_reg reglist[],
+ int len)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret = 0;
+ unsigned int k = 0, j = 0;
+ int i = 0;
+ struct i2c_msg *msg;
+ unsigned char *data;
+ unsigned int max_entries = len;
+
+ msg = kmalloc((sizeof(struct i2c_msg) * I2C_MSG_MAX), GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+ data = kmalloc((sizeof(unsigned char) * I2C_DATA_MAX), GFP_KERNEL);
+ if (!data) {
+ kfree(msg);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < max_entries; i++) {
+ switch (reglist[i].flag) {
+ case PLTFRM_CAMERA_MODULE_REG_TYPE_DATA:
+ (msg + j)->addr = client->addr;
+ (msg + j)->flags = I2C_M_WR;
+ (msg + j)->len = 4;
+ (msg + j)->buf = (data + k);
+
+ data[k + 0] = (u8)((reglist[i].reg >> 8) & 0xFF);
+ data[k + 1] = (u8)(reglist[i].reg & 0xFF);
+ data[k + 2] = (u8)((reglist[i].val >> 8) & 0xFF);
+ data[k + 3] = (u8)(reglist[i].val & 0xFF);
+
+ k = k + 4;
+ j++;
+ if (j == (I2C_MSG_MAX - 1)) {
+ /* Bulk I2C transfer */
+ pltfrm_camera_module_pr_err(sd,
+ "messages transfers 1 0x%p msg %d bytes %d\n",
+ msg, j, k);
+ ret = i2c_transfer(client->adapter, msg, j);
+ if (ret < 0) {
+ pltfrm_camera_module_pr_err(sd,
+ "i2c transfer returned with err %d\n",
+ ret);
+ kfree(msg);
+ kfree(data);
+ return ret;
+ }
+ j = 0;
+ k = 0;
+ pltfrm_camera_module_pr_debug(sd,
+ "i2c_transfer return %d\n", ret);
+ }
+ break;
+ case PLTFRM_CAMERA_MODULE_REG_TYPE_TIMEOUT:
+ if (j > 0) {
+ /* Bulk I2C transfer */
+ pltfrm_camera_module_pr_debug(sd,
+ "messages transfers 1 0x%p msg %d bytes %d\n",
+ msg, j, k);
+ ret = i2c_transfer(client->adapter, msg, j);
+ if (ret < 0) {
+ pltfrm_camera_module_pr_debug(sd,
+ "i2c transfer returned with err %d\n",
+ ret);
+ kfree(msg);
+ kfree(data);
+ return ret;
+ }
+ pltfrm_camera_module_pr_debug(sd,
+ "i2c_transfer return %d\n", ret);
+ }
+ mdelay(reglist[i].val);
+ j = 0;
+ k = 0;
+ break;
+ default:
+ pltfrm_camera_module_pr_debug(sd, "unknown command\n");
+ kfree(msg);
+ kfree(data);
+ return -1;
+ }
+ }
+
+ if (j != 0) { /*Remaining I2C message*/
+ pltfrm_camera_module_pr_debug(sd,
+ "messages transfers 1 0x%p msg %d bytes %d\n",
+ msg, j, k);
+ ret = i2c_transfer(client->adapter, msg, j);
+ if (ret < 0) {
+ pltfrm_camera_module_pr_err(sd,
+ "i2c transfer returned with err %d\n", ret);
+ kfree(msg);
+ kfree(data);
+ return ret;
+ }
+ pltfrm_camera_module_pr_debug(sd,
+ "i2c_transfer return %d\n", ret);
+ }
+
+ kfree(msg);
+ kfree(data);
+ return 0;
+}
+
+static void aptina_camera_module_set_active_config(
+ struct aptina_camera_module *cam_mod,
+ struct aptina_camera_module_config *new_config)
+{
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "\n");
+
+ if (IS_ERR_OR_NULL(new_config)) {
+ cam_mod->active_config = new_config;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "no active config\n");
+ } else {
+ cam_mod->ctrl_updt &= APTINA_CAMERA_MODULE_CTRL_UPDT_AUTO_EXP |
+ APTINA_CAMERA_MODULE_CTRL_UPDT_AUTO_GAIN |
+ APTINA_CAMERA_MODULE_CTRL_UPDT_AUTO_WB;
+ if (new_config->auto_exp_enabled !=
+ cam_mod->exp_config.auto_exp) {
+ cam_mod->ctrl_updt |=
+ APTINA_CAMERA_MODULE_CTRL_UPDT_AUTO_EXP;
+ cam_mod->exp_config.auto_exp =
+ new_config->auto_exp_enabled;
+ }
+ if (new_config->auto_gain_enabled !=
+ cam_mod->exp_config.auto_gain) {
+ cam_mod->ctrl_updt |=
+ APTINA_CAMERA_MODULE_CTRL_UPDT_AUTO_GAIN;
+ cam_mod->exp_config.auto_gain =
+ new_config->auto_gain_enabled;
+ }
+ if (new_config->auto_wb_enabled !=
+ cam_mod->wb_config.auto_wb) {
+ cam_mod->ctrl_updt |=
+ APTINA_CAMERA_MODULE_CTRL_UPDT_AUTO_WB;
+ cam_mod->wb_config.auto_wb =
+ new_config->auto_wb_enabled;
+ }
+ if (new_config != cam_mod->active_config) {
+ cam_mod->update_config = true;
+ cam_mod->active_config = new_config;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "activating config '%s'\n",
+ new_config->name);
+ }
+ }
+}
+
+/* ======================================================================== */
+
+static struct aptina_camera_module_config *aptina_camera_module_find_config(
+ struct aptina_camera_module *cam_mod,
+ struct v4l2_mbus_framefmt *fmt,
+ struct v4l2_subdev_frame_interval *frm_intrvl)
+{
+ u32 i;
+ unsigned long gcdiv;
+ struct v4l2_subdev_frame_interval norm_interval;
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "\n");
+ if (!IS_ERR_OR_NULL(fmt))
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "%dx%d, fmt code 0x%04x\n",
+ fmt->width, fmt->height, fmt->code);
+
+ if (!IS_ERR_OR_NULL(frm_intrvl))
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "frame interval %d/%d\n",
+ frm_intrvl->interval.numerator,
+ frm_intrvl->interval.denominator);
+
+ for (i = 0; i < cam_mod->custom.num_configs; i++) {
+ if (!IS_ERR_OR_NULL(frm_intrvl)) {
+ gcdiv = gcd(cam_mod->custom.configs[i].
+ frm_intrvl.interval.numerator,
+ cam_mod->custom.configs[i].
+ frm_intrvl.interval.denominator);
+ norm_interval.interval.numerator =
+ cam_mod->custom.configs[i].
+ frm_intrvl.interval.numerator / gcdiv;
+ norm_interval.interval.denominator =
+ cam_mod->custom.configs[i].
+ frm_intrvl.interval.denominator / gcdiv;
+ if ((frm_intrvl->interval.numerator !=
+ norm_interval.interval.numerator) ||
+ (frm_intrvl->interval.denominator !=
+ norm_interval.interval.denominator))
+ continue;
+ }
+ if (!IS_ERR_OR_NULL(fmt)) {
+ if ((cam_mod->custom.configs[i].frm_fmt.width !=
+ fmt->width) ||
+ (cam_mod->custom.configs[i].frm_fmt.height !=
+ fmt->height) ||
+ (cam_mod->custom.configs[i].frm_fmt.code !=
+ fmt->code)) {
+ continue;
+ }
+ }
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "found matching config %s\n",
+ cam_mod->custom.configs[i].name);
+ return &cam_mod->custom.configs[i];
+ }
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "no matching config found\n");
+
+ return ERR_PTR(-EINVAL);
+}
+
+/* ======================================================================== */
+
+static int aptina_camera_module_write_config(
+ struct aptina_camera_module *cam_mod)
+{
+ int ret = 0;
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "\n");
+
+ if (IS_ERR_OR_NULL(cam_mod->active_config)) {
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "no active sensor configuration");
+ ret = -EFAULT;
+ goto err;
+ }
+
+ ret = aptina_write_reglist(&cam_mod->sd,
+ cam_mod->active_config->reg_table,
+ cam_mod->active_config->reg_table_num_entries);
+ if (IS_ERR_VALUE(ret))
+ goto err;
+ ret = pltfrm_camera_module_patch_config(&cam_mod->sd,
+ &cam_mod->frm_fmt,
+ &cam_mod->frm_intrvl);
+ if (IS_ERR_VALUE(ret))
+ goto err;
+
+ return 0;
+err:
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "failed with error %d\n", ret);
+ return ret;
+}
+
+static int aptina_camera_module_attach(
+ struct aptina_camera_module *cam_mod)
+{
+ int ret = 0;
+ struct aptina_camera_module_custom_config *custom;
+
+ custom = &cam_mod->custom;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "\n");
+ if (custom->check_camera_id) {
+ aptina_camera_module_s_power(&cam_mod->sd, 1);
+ ret = custom->check_camera_id(cam_mod);
+ aptina_camera_module_s_power(&cam_mod->sd, 0);
+ if (ret != 0)
+ goto err;
+ }
+
+ return 0;
+
+err:
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "failed with error %d\n", ret);
+ aptina_camera_module_release(cam_mod);
+ return ret;
+}
+
+/* ======================================================================== */
+
+int aptina_camera_module_try_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *fmt)
+{
+ struct aptina_camera_module *cam_mod = to_aptina_camera_module(sd);
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "%dx%d, fmt code 0x%04x\n",
+ fmt->width, fmt->height, fmt->code);
+
+ if (IS_ERR_OR_NULL(
+ aptina_camera_module_find_config(
+ cam_mod, fmt, NULL))) {
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "format not supported\n");
+ return -EINVAL;
+ }
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "format supported\n");
+
+ return 0;
+}
+
+/* ======================================================================== */
+
+int aptina_camera_module_s_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format)
+{
+ struct aptina_camera_module *cam_mod = to_aptina_camera_module(sd);
+ struct v4l2_mbus_framefmt *fmt = &format->format;
+ int ret = 0;
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "%dx%d, fmt code 0x%04x\n",
+ fmt->width, fmt->height, fmt->code);
+
+ if (IS_ERR_OR_NULL(
+ aptina_camera_module_find_config(
+ cam_mod, fmt, NULL))) {
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "format %dx%d, code 0x%04x, not supported\n",
+ fmt->width, fmt->height, fmt->code);
+ ret = -EINVAL;
+ goto err;
+ }
+ cam_mod->frm_fmt_valid = true;
+ cam_mod->frm_fmt = *fmt;
+ if (cam_mod->frm_intrvl_valid) {
+ aptina_camera_module_set_active_config(cam_mod,
+ aptina_camera_module_find_config(cam_mod,
+ fmt, &cam_mod->frm_intrvl));
+ }
+ return 0;
+err:
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "failed with error %d\n", ret);
+ return ret;
+}
+
+/* ======================================================================== */
+
+int aptina_camera_module_g_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format)
+{
+ struct aptina_camera_module *cam_mod = to_aptina_camera_module(sd);
+ struct v4l2_mbus_framefmt *fmt = &format->format;
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "\n");
+
+ if (cam_mod->active_config) {
+ fmt->code = cam_mod->active_config->frm_fmt.code;
+ fmt->width = cam_mod->active_config->frm_fmt.width;
+ fmt->height = cam_mod->active_config->frm_fmt.height;
+ return 0;
+ }
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "no active config\n");
+
+ return -1;
+}
+
+/* ======================================================================== */
+
+int aptina_camera_module_s_frame_interval(
+ struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *interval)
+{
+ struct aptina_camera_module *cam_mod = to_aptina_camera_module(sd);
+ unsigned long gcdiv;
+ struct v4l2_subdev_frame_interval norm_interval;
+ int ret = 0;
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "\n");
+ if ((interval->interval.denominator == 0) ||
+ (interval->interval.numerator == 0)) {
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "invalid frame interval %d/%d\n",
+ interval->interval.numerator,
+ interval->interval.denominator);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "%d/%d (%dfps)\n",
+ interval->interval.numerator, interval->interval.denominator,
+ (interval->interval.denominator +
+ (interval->interval.numerator >> 1)) /
+ interval->interval.numerator);
+
+ /* normalize interval */
+ gcdiv = gcd(interval->interval.numerator,
+ interval->interval.denominator);
+ norm_interval.interval.numerator =
+ interval->interval.numerator / gcdiv;
+ norm_interval.interval.denominator =
+ interval->interval.denominator / gcdiv;
+
+ if (IS_ERR_OR_NULL(aptina_camera_module_find_config(cam_mod,
+ NULL, &norm_interval))) {
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "frame interval %d/%d not supported\n",
+ interval->interval.numerator,
+ interval->interval.denominator);
+ ret = -EINVAL;
+ goto err;
+ }
+ cam_mod->frm_intrvl_valid = true;
+ cam_mod->frm_intrvl = norm_interval;
+ if (cam_mod->frm_fmt_valid) {
+ aptina_camera_module_set_active_config(cam_mod,
+ aptina_camera_module_find_config(cam_mod,
+ &cam_mod->frm_fmt, interval));
+ }
+ return 0;
+err:
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "failed with error %d\n", ret);
+ return ret;
+}
+
+/* ======================================================================== */
+
+int aptina_camera_module_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ int ret = 0;
+ struct aptina_camera_module *cam_mod = to_aptina_camera_module(sd);
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "%d\n", enable);
+
+ if (enable) {
+ if (cam_mod->state == APTINA_CAMERA_MODULE_STREAMING)
+ return 0;
+ if (IS_ERR_OR_NULL(cam_mod->active_config)) {
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "no active sensor configuration, cannot start streaming\n");
+ ret = -EFAULT;
+ goto err;
+ }
+ if (cam_mod->state != APTINA_CAMERA_MODULE_SW_STANDBY) {
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "sensor is not powered on (in state %d), cannot start streaming\n",
+ cam_mod->state);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (!IS_ERR_OR_NULL(cam_mod->custom.set_flip))
+ cam_mod->custom.set_flip(cam_mod);
+
+ if (cam_mod->update_config)
+ ret = aptina_camera_module_write_config(cam_mod);
+ if (IS_ERR_VALUE(ret))
+ goto err;
+
+ ret = cam_mod->custom.start_streaming(cam_mod);
+ if (IS_ERR_VALUE(ret))
+ goto err;
+ cam_mod->update_config = false;
+ cam_mod->ctrl_updt = 0;
+ mdelay(cam_mod->custom.power_up_delays_ms[2]);
+ cam_mod->state = APTINA_CAMERA_MODULE_STREAMING;
+ } else {
+ int pclk;
+ int wait_ms;
+ struct isp_supplemental_sensor_mode_data timings;
+
+ if (cam_mod->state != APTINA_CAMERA_MODULE_STREAMING)
+ return 0;
+ ret = cam_mod->custom.stop_streaming(cam_mod);
+ if (IS_ERR_VALUE(ret))
+ goto err;
+
+ cam_mod->state = APTINA_CAMERA_MODULE_SW_STANDBY;
+
+ ret = aptina_camera_module_ioctl(sd, RK_VIDIOC_SENSOR_MODE_DATA,
+ &timings);
+ if (IS_ERR_VALUE(ret))
+ goto err;
+ pclk = timings.vt_pix_clk_freq_hz / 1000;
+ if (!pclk)
+ goto err;
+ wait_ms = (timings.line_length_pck
+ * timings.frame_length_lines) / pclk;
+ /* wait for a frame period to make sure that there is
+ *no pending frame left.
+ */
+ msleep(wait_ms + 1);
+ }
+
+ cam_mod->state_before_suspend = cam_mod->state;
+
+ return 0;
+err:
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "failed with error %d\n", ret);
+ return ret;
+}
+
+/* ======================================================================== */
+
+int aptina_camera_module_s_power(struct v4l2_subdev *sd, int on)
+{
+ int ret = 0;
+ struct aptina_camera_module *cam_mod = to_aptina_camera_module(sd);
+ struct v4l2_subdev *af_ctrl;
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "%d\n", on);
+
+ if (on) {
+ if (cam_mod->state == APTINA_CAMERA_MODULE_POWER_OFF) {
+ ret = pltfrm_camera_module_s_power(&cam_mod->sd, 1);
+ if (!IS_ERR_VALUE(ret)) {
+ mdelay(cam_mod->custom.power_up_delays_ms[0]);
+ cam_mod->state =
+ APTINA_CAMERA_MODULE_HW_STANDBY;
+ }
+ }
+ if (cam_mod->state == APTINA_CAMERA_MODULE_HW_STANDBY) {
+ ret = pltfrm_camera_module_set_pin_state(&cam_mod->sd,
+ PLTFRM_CAMERA_MODULE_PIN_PWR,
+ PLTFRM_CAMERA_MODULE_PIN_STATE_ACTIVE);
+ msleep(20);
+
+ ret = pltfrm_camera_module_set_pin_state(
+ &cam_mod->sd,
+ PLTFRM_CAMERA_MODULE_PIN_PD,
+ PLTFRM_CAMERA_MODULE_PIN_STATE_ACTIVE);
+ msleep(20);
+
+ ret = pltfrm_camera_module_set_pin_state(
+ &cam_mod->sd,
+ PLTFRM_CAMERA_MODULE_PIN_RESET,
+ PLTFRM_CAMERA_MODULE_PIN_STATE_ACTIVE);
+ msleep(20);
+
+ ret = pltfrm_camera_module_set_pin_state(
+ &cam_mod->sd,
+ PLTFRM_CAMERA_MODULE_PIN_RESET,
+ PLTFRM_CAMERA_MODULE_PIN_STATE_INACTIVE);
+ msleep(20);
+
+ ret = pltfrm_camera_module_set_pin_state(
+ &cam_mod->sd,
+ PLTFRM_CAMERA_MODULE_PIN_RESET,
+ PLTFRM_CAMERA_MODULE_PIN_STATE_ACTIVE);
+ msleep(20);
+
+ ret = pltfrm_camera_module_set_pin_state(
+ &cam_mod->sd,
+ PLTFRM_CAMERA_MODULE_PIN_PD,
+ PLTFRM_CAMERA_MODULE_PIN_STATE_INACTIVE);
+ msleep(20);
+ ret = pltfrm_camera_module_set_pin_state(
+ &cam_mod->sd,
+ PLTFRM_CAMERA_MODULE_PIN_PD,
+ PLTFRM_CAMERA_MODULE_PIN_STATE_ACTIVE);
+ msleep(20);
+
+ if (!IS_ERR_VALUE(ret)) {
+ mdelay(cam_mod->custom.power_up_delays_ms[1]);
+ cam_mod->state =
+ APTINA_CAMERA_MODULE_SW_STANDBY;
+
+ #if 1
+ if (!IS_ERR_OR_NULL(
+ cam_mod->custom.init_common) &&
+ cam_mod->custom.init_common(
+ cam_mod))
+ usleep_range(1000, 1500);
+ #endif
+
+ af_ctrl = pltfrm_camera_module_get_af_ctrl(sd);
+ if (!IS_ERR_OR_NULL(af_ctrl)) {
+ v4l2_subdev_call(af_ctrl,
+ core, init, 0);
+ }
+ }
+ }
+ } else {
+ if (cam_mod->state == APTINA_CAMERA_MODULE_STREAMING) {
+ ret = aptina_camera_module_s_stream(sd, 0);
+ if (!IS_ERR_VALUE(ret))
+ cam_mod->state =
+ APTINA_CAMERA_MODULE_SW_STANDBY;
+ }
+ if (cam_mod->state == APTINA_CAMERA_MODULE_SW_STANDBY) {
+ ret = pltfrm_camera_module_set_pin_state(
+ &cam_mod->sd,
+ PLTFRM_CAMERA_MODULE_PIN_PD,
+ PLTFRM_CAMERA_MODULE_PIN_STATE_INACTIVE);
+
+ ret = pltfrm_camera_module_set_pin_state(
+ &cam_mod->sd,
+ PLTFRM_CAMERA_MODULE_PIN_RESET,
+ PLTFRM_CAMERA_MODULE_PIN_STATE_INACTIVE);
+
+ ret = pltfrm_camera_module_set_pin_state(
+ &cam_mod->sd,
+ PLTFRM_CAMERA_MODULE_PIN_PWR,
+ PLTFRM_CAMERA_MODULE_PIN_STATE_INACTIVE);
+
+ if (!IS_ERR_VALUE(ret))
+ cam_mod->state =
+ APTINA_CAMERA_MODULE_HW_STANDBY;
+ }
+ if (cam_mod->state == APTINA_CAMERA_MODULE_HW_STANDBY) {
+ ret = pltfrm_camera_module_s_power(&cam_mod->sd, 0);
+ if (!IS_ERR_VALUE(ret)) {
+ cam_mod->state = APTINA_CAMERA_MODULE_POWER_OFF;
+ aptina_camera_module_reset(cam_mod);
+ }
+ }
+ }
+
+ cam_mod->state_before_suspend = cam_mod->state;
+
+ if (IS_ERR_VALUE(ret)) {
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "%s failed, camera left in state %d\n",
+ on ? "on" : "off", cam_mod->state);
+ goto err;
+ } else
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "camera powered %s\n", on ? "on" : "off");
+
+ return 0;
+err:
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "failed with error %d\n", ret);
+ return ret;
+}
+
+/* ======================================================================== */
+
+int aptina_camera_module_g_ctrl(struct v4l2_subdev *sd,
+ struct v4l2_control *ctrl)
+{
+ struct aptina_camera_module *cam_mod = to_aptina_camera_module(sd);
+ int ret;
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, " id 0x%x\n", ctrl->id);
+
+ if (ctrl->id == V4L2_CID_FLASH_LED_MODE) {
+ ctrl->value = cam_mod->exp_config.flash_mode;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_FLASH_LED_MODE %d\n",
+ ctrl->value);
+ return 0;
+ }
+
+ if (IS_ERR_OR_NULL(cam_mod->active_config)) {
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "no active configuration\n");
+ return -EFAULT;
+ }
+
+ if (ctrl->id == RK_V4L2_CID_VBLANKING) {
+ ctrl->value = cam_mod->active_config->v_blanking_time_us;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "RK_V4L2_CID_VBLANKING %d\n",
+ ctrl->value);
+ return 0;
+ }
+
+/*
+ *if (ctrl->id == RK_V4L2_CID_IGNORE_MEASUREMENT_CHECK) {
+ * ctrl->value = cam_mod->active_config->ignore_measurement_check;
+ * pltfrm_camera_module_pr_debug(
+ * &cam_mod->sd,
+ * "CIF_ISP20_CID_IGNORE_MEASUREMENT_CHECK %d\n",
+ * ctrl->value);
+ * return 0;
+ * }
+ */
+
+ if ((cam_mod->state != APTINA_CAMERA_MODULE_SW_STANDBY) &&
+ (cam_mod->state != APTINA_CAMERA_MODULE_STREAMING)) {
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "cannot get controls when camera is off\n");
+ return -EFAULT;
+ }
+
+ if (ctrl->id == V4L2_CID_FOCUS_ABSOLUTE) {
+ struct v4l2_subdev *af_ctrl;
+
+ af_ctrl =
+ pltfrm_camera_module_get_af_ctrl(sd);
+ if (!IS_ERR_OR_NULL(af_ctrl)) {
+ ret = v4l2_subdev_call(af_ctrl, core, g_ctrl, ctrl);
+ return ret;
+ }
+ }
+
+ if (!IS_ERR_OR_NULL(cam_mod->custom.g_ctrl)) {
+ ret = cam_mod->custom.g_ctrl(cam_mod, ctrl->id);
+ if (IS_ERR_VALUE(ret))
+ return ret;
+ }
+
+ switch (ctrl->id) {
+ case V4L2_CID_GAIN:
+ ctrl->value = cam_mod->exp_config.gain;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_GAIN %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_EXPOSURE:
+ ctrl->value = cam_mod->exp_config.exp_time;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_EXPOSURE %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_WHITE_BALANCE_TEMPERATURE:
+ ctrl->value = cam_mod->wb_config.temperature;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_WHITE_BALANCE_TEMPERATURE %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_AUTOGAIN:
+ ctrl->value = cam_mod->exp_config.auto_gain;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_AUTOGAIN %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_EXPOSURE_AUTO:
+ ctrl->value = cam_mod->exp_config.auto_exp;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_EXPOSURE_AUTO %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ ctrl->value = cam_mod->wb_config.auto_wb;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_AUTO_WHITE_BALANCE %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_FOCUS_ABSOLUTE:
+ ctrl->value = cam_mod->af_config.abs_pos;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_FOCUS_ABSOLUTE %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_HFLIP:
+ case V4L2_CID_VFLIP:
+ /* TBD */
+ /* fallthrough */
+ default:
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "failed, unknown ctrl %d\n", ctrl->id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* ======================================================================== */
+
+static int flash_light_ctrl(
+ struct v4l2_subdev *sd,
+ struct aptina_camera_module *cam_mod,
+ int value)
+{
+ return 0;
+}
+
+/* ======================================================================== */
+
+int aptina_camera_module_s_ext_ctrls(
+ struct v4l2_subdev *sd,
+ struct v4l2_ext_controls *ctrls)
+{
+ int i;
+ int ctrl_cnt = 0;
+ struct aptina_camera_module *cam_mod = to_aptina_camera_module(sd);
+ int ret = 0;
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "\n");
+
+ if (ctrls->count == 0)
+ return -EINVAL;
+
+ for (i = 0; i < ctrls->count; i++) {
+ struct v4l2_ext_control *ctrl;
+ u32 ctrl_updt = 0;
+
+ ctrl = &ctrls->controls[i];
+
+ switch (ctrl->id) {
+ case V4L2_CID_GAIN:
+ ctrl_updt = APTINA_CAMERA_MODULE_CTRL_UPDT_GAIN;
+ cam_mod->exp_config.gain = ctrl->value;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_GAIN %d\n",
+ ctrl->value);
+ break;
+ case RK_V4L2_CID_GAIN_PERCENT:
+ ctrl_updt = APTINA_CAMERA_MODULE_CTRL_UPDT_GAIN;
+ cam_mod->exp_config.gain_percent = ctrl->value;
+ break;
+ case V4L2_CID_FLASH_LED_MODE:
+ ret = flash_light_ctrl(sd, cam_mod, ctrl->value);
+ if (ret == 0) {
+ cam_mod->exp_config.flash_mode = ctrl->value;
+ pltfrm_camera_module_pr_debug(
+ &cam_mod->sd,
+ "V4L2_CID_FLASH_LED_MODE %d\n",
+ ctrl->value);
+ }
+ break;
+ case V4L2_CID_EXPOSURE:
+ ctrl_updt = APTINA_CAMERA_MODULE_CTRL_UPDT_EXP_TIME;
+ cam_mod->exp_config.exp_time = ctrl->value;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_EXPOSURE %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_WHITE_BALANCE_TEMPERATURE:
+ ctrl_updt =
+ APTINA_CAMERA_MODULE_CTRL_UPDT_WB_TEMPERATURE;
+ cam_mod->wb_config.temperature = ctrl->value;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_WHITE_BALANCE_TEMPERATURE %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_AUTOGAIN:
+ ctrl_updt = APTINA_CAMERA_MODULE_CTRL_UPDT_AUTO_GAIN;
+ cam_mod->exp_config.auto_gain = ctrl->value;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_AUTOGAIN %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_EXPOSURE_AUTO:
+ ctrl_updt = APTINA_CAMERA_MODULE_CTRL_UPDT_AUTO_EXP;
+ cam_mod->exp_config.auto_exp = ctrl->value;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_EXPOSURE_AUTO %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ ctrl_updt = APTINA_CAMERA_MODULE_CTRL_UPDT_AUTO_WB;
+ cam_mod->wb_config.auto_wb = ctrl->value;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_AUTO_WHITE_BALANCE %d\n",
+ ctrl->value);
+ break;
+ case RK_V4L2_CID_AUTO_FPS:
+ cam_mod->auto_adjust_fps = ctrl->value;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "RK_V4L2_CID_AUTO_FPS %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_FOCUS_ABSOLUTE:
+ {
+ struct v4l2_subdev *af_ctrl;
+
+ af_ctrl = pltfrm_camera_module_get_af_ctrl(sd);
+ if (!IS_ERR_OR_NULL(af_ctrl)) {
+ struct v4l2_control single_ctrl;
+
+ single_ctrl.id =
+ V4L2_CID_FOCUS_ABSOLUTE;
+ single_ctrl.value = ctrl->value;
+ ret = v4l2_subdev_call(af_ctrl,
+ core, s_ctrl, &single_ctrl);
+ return ret;
+ }
+ }
+ ctrl_updt =
+ APTINA_CAMERA_MODULE_CTRL_UPDT_FOCUS_ABSOLUTE;
+ cam_mod->af_config.abs_pos = ctrl->value;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_FOCUS_ABSOLUTE %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_HFLIP:
+ if (ctrl->value)
+ cam_mod->hflip = true;
+ else
+ cam_mod->hflip = false;
+ break;
+ case V4L2_CID_VFLIP:
+ if (ctrl->value)
+ cam_mod->vflip = true;
+ else
+ cam_mod->vflip = false;
+ break;
+ default:
+ pltfrm_camera_module_pr_warn(&cam_mod->sd,
+ "ignoring unknown ctrl 0x%x\n", ctrl->id);
+ break;
+ }
+
+ if (cam_mod->state != APTINA_CAMERA_MODULE_SW_STANDBY &&
+ cam_mod->state != APTINA_CAMERA_MODULE_STREAMING)
+ cam_mod->ctrl_updt |= ctrl_updt;
+ else if (ctrl_updt)
+ ctrl_cnt++;
+ }
+
+ /* if camera module is already streaming, write through */
+ if (ctrl_cnt &&
+ (cam_mod->state == APTINA_CAMERA_MODULE_STREAMING ||
+ cam_mod->state == APTINA_CAMERA_MODULE_SW_STANDBY)) {
+ struct aptina_camera_module_ext_ctrls aptina_ctrls;
+
+ aptina_ctrls.ctrls =
+ (struct aptina_camera_module_ext_ctrl *)
+ kmalloc(ctrl_cnt * sizeof(struct aptina_camera_module_ext_ctrl),
+ GFP_KERNEL);
+
+ if (aptina_ctrls.ctrls) {
+ for (i = 0; i < ctrl_cnt; i++) {
+ aptina_ctrls.ctrls[i].id =
+ ctrls->controls[i].id;
+ aptina_ctrls.ctrls[i].value =
+ ctrls->controls[i].value;
+ }
+
+ aptina_ctrls.count = ctrl_cnt;
+
+ ret = cam_mod->custom.s_ext_ctrls(cam_mod,
+ &aptina_ctrls);
+
+ kfree(aptina_ctrls.ctrls);
+ } else {
+ ret = -ENOMEM;
+ }
+
+ if (IS_ERR_VALUE(ret))
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "failed with error %d\n", ret);
+ }
+
+ return ret;
+}
+
+/* ======================================================================== */
+
+int aptina_camera_module_s_ctrl(
+ struct v4l2_subdev *sd,
+ struct v4l2_control *ctrl)
+{
+ struct aptina_camera_module *cam_mod = to_aptina_camera_module(sd);
+ struct v4l2_ext_control ext_ctrl[1];
+ struct v4l2_ext_controls ext_ctrls;
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "0x%x 0x%x\n", ctrl->id, ctrl->value);
+
+ ext_ctrl[0].id = ctrl->id;
+ ext_ctrl[0].value = ctrl->value;
+
+ ext_ctrls.count = 1;
+ ext_ctrls.controls = ext_ctrl;
+
+ return aptina_camera_module_s_ext_ctrls(sd, &ext_ctrls);
+}
+
+/* ======================================================================== */
+
+long aptina_camera_module_ioctl(struct v4l2_subdev *sd,
+ unsigned int cmd,
+ void *arg)
+{
+ struct aptina_camera_module *cam_mod = to_aptina_camera_module(sd);
+ int ret;
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "\n");
+
+ if (cmd == RK_VIDIOC_SENSOR_MODE_DATA) {
+ struct aptina_camera_module_timings aptina_timings;
+ struct isp_supplemental_sensor_mode_data *timings =
+ (struct isp_supplemental_sensor_mode_data *)arg;
+
+ if (cam_mod->custom.g_timings)
+ ret = cam_mod->custom.g_timings(cam_mod,
+ &aptina_timings);
+ else
+ ret = -EPERM;
+
+ if (IS_ERR_VALUE(ret)) {
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "failed with error %d\n", ret);
+ return ret;
+ }
+
+ timings->sensor_output_width =
+ aptina_timings.sensor_output_width;
+ timings->sensor_output_height =
+ aptina_timings.sensor_output_height;
+ timings->crop_horizontal_start =
+ aptina_timings.crop_horizontal_start;
+ timings->crop_vertical_start =
+ aptina_timings.crop_vertical_start;
+ timings->crop_horizontal_end =
+ aptina_timings.crop_horizontal_end;
+ timings->crop_vertical_end =
+ aptina_timings.crop_vertical_end;
+ timings->line_length_pck =
+ aptina_timings.line_length_pck;
+ timings->frame_length_lines =
+ aptina_timings.frame_length_lines;
+ timings->vt_pix_clk_freq_hz =
+ aptina_timings.vt_pix_clk_freq_hz;
+ timings->binning_factor_x =
+ aptina_timings.binning_factor_x;
+ timings->binning_factor_y =
+ aptina_timings.binning_factor_y;
+ timings->coarse_integration_time_max_margin =
+ aptina_timings.coarse_integration_time_max_margin;
+ timings->coarse_integration_time_min =
+ aptina_timings.coarse_integration_time_min;
+ timings->fine_integration_time_max_margin =
+ aptina_timings.fine_integration_time_max_margin;
+ timings->fine_integration_time_min =
+ aptina_timings.fine_integration_time_min;
+
+ if (cam_mod->custom.g_exposure_valid_frame)
+ timings->exposure_valid_frame =
+ cam_mod->custom.g_exposure_valid_frame(cam_mod);
+
+ /*
+ *timings->exp_time = cam_mod->exp_config.exp_time;
+ *timings->gain = cam_mod->exp_config.gain;
+ */
+
+ return ret;
+ } else if (cmd == PLTFRM_CIFCAM_G_ITF_CFG) {
+ struct pltfrm_cam_itf *itf_cfg = (struct pltfrm_cam_itf *)arg;
+ struct aptina_camera_module_config *config;
+
+ if (cam_mod->custom.num_configs <= 0) {
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "cam_mod->custom.num_configs is NULL, Get interface config failed!\n");
+ return -EINVAL;
+ }
+
+ if (IS_ERR_OR_NULL(cam_mod->active_config))
+ config = &cam_mod->custom.configs[0];
+ else
+ config = cam_mod->active_config;
+
+ *itf_cfg = config->itf_cfg;
+ pltfrm_camera_module_ioctl(sd, PLTFRM_CIFCAM_G_ITF_CFG, arg);
+ return 0;
+ } else if (cmd == PLTFRM_CIFCAM_ATTACH) {
+ aptina_camera_module_init(cam_mod, &cam_mod->custom);
+ pltfrm_camera_module_ioctl(sd, cmd, arg);
+ return aptina_camera_module_attach(cam_mod);
+ }
+
+ ret = pltfrm_camera_module_ioctl(sd, cmd, arg);
+ return ret;
+}
+
+/* Reconfigure bayer order according to xml's definition */
+static int aptina_camera_module_s_flip(struct aptina_camera_module *cam_mod)
+{
+ int i, mode = 0;
+ static int flip_mode;
+
+ if (!cam_mod->custom.configs->bayer_order_alter_enble) {
+ aptina_camera_module_pr_info(cam_mod,
+ "not need to change bayer order!");
+ return 0;
+ }
+
+ mode = pltfrm_camera_module_get_flip_mirror(&cam_mod->sd);
+
+ aptina_camera_module_pr_debug(cam_mod,
+ "%s(%d): flip_mode is %d, mode is %d.\n",
+ __func__,
+ __LINE__,
+ flip_mode,
+ mode);
+
+ if (mode != flip_mode) {
+ /* Reconfigure the compatible bayer order */
+ switch (mode) {
+ case 0:
+ /* Change all the bayter order of registered configs */
+ for (i = 0; i < cam_mod->custom.num_configs; i++)
+ cam_mod->custom.configs[i].frm_fmt.code =
+ MEDIA_BUS_FMT_SGRBG10_1X10;
+ break;
+
+ case 1:
+ for (i = 0; i < cam_mod->custom.num_configs; i++)
+ cam_mod->custom.configs[i].frm_fmt.code =
+ MEDIA_BUS_FMT_SRGGB10_1X10;
+ break;
+
+ case 2:
+ for (i = 0; i < cam_mod->custom.num_configs; i++)
+ cam_mod->custom.configs[i].frm_fmt.code =
+ MEDIA_BUS_FMT_SBGGR10_1X10;
+ break;
+
+ case 3:
+ for (i = 0; i < cam_mod->custom.num_configs; i++)
+ cam_mod->custom.configs[i].frm_fmt.code =
+ MEDIA_BUS_FMT_SGBRG10_1X10;
+ break;
+
+ default:
+ break;
+ };
+ }
+
+ flip_mode = mode;
+
+ return 0;
+}
+
+int aptina_camera_module_get_flip_mirror(
+ struct aptina_camera_module *cam_mod)
+{
+ return pltfrm_camera_module_get_flip_mirror(&cam_mod->sd);
+}
+
+int aptina_camera_module_enum_frameintervals(
+ struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_interval_enum *file)
+{
+ struct aptina_camera_module *cam_mod = to_aptina_camera_module(sd);
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "%d\n", file->index);
+
+ if (file->index >= cam_mod->custom.num_configs)
+ return -EINVAL;
+
+ aptina_camera_module_s_flip(cam_mod);
+ file->code =
+ cam_mod->custom.configs[file->index].frm_fmt.code;
+ file->width = cam_mod->custom.configs[file->index].frm_fmt.width;
+ file->height = cam_mod->custom.configs[file->index].frm_fmt.height;
+ file->interval.numerator = cam_mod->custom.
+ configs[file->index].frm_intrvl.interval.numerator;
+ file->interval.denominator = cam_mod->custom.
+ configs[file->index].frm_intrvl.interval.denominator;
+ return 0;
+}
+
+/* ======================================================================== */
+
+int aptina_camera_module_write_reglist(
+ struct aptina_camera_module *cam_mod,
+ const struct aptina_camera_module_reg reglist[],
+ int len)
+{
+ return aptina_write_reglist(&cam_mod->sd, reglist, len);
+}
+
+/* ======================================================================== */
+
+int aptina_camera_module_write_reg(
+ struct aptina_camera_module *cam_mod,
+ u16 reg,
+ u16 val)
+{
+ return aptina_write_i2c_reg(&cam_mod->sd, reg, val);
+}
+
+/* ======================================================================== */
+
+int aptina_camera_module_read_reg(
+ struct aptina_camera_module *cam_mod,
+ u16 data_length,
+ u16 reg,
+ u32 *val)
+{
+ return aptina_read_i2c_reg(&cam_mod->sd,
+ data_length, reg, val);
+}
+
+/* ======================================================================== */
+
+int aptina_camera_module_read_reg_table(
+ struct aptina_camera_module *cam_mod,
+ u16 reg,
+ u32 *val)
+{
+ int i;
+
+ if (cam_mod->state == APTINA_CAMERA_MODULE_STREAMING)
+ return aptina_read_i2c_reg(&cam_mod->sd,
+ 1, reg, val);
+
+ if (!IS_ERR_OR_NULL(cam_mod->active_config)) {
+ for (
+ i = cam_mod->active_config->reg_table_num_entries - 1;
+ i > 0;
+ i--) {
+ if (cam_mod->active_config->reg_table[i].reg == reg) {
+ *val = cam_mod->active_config->reg_table[i].val;
+ return 0;
+ }
+ }
+ }
+
+ if (cam_mod->state == APTINA_CAMERA_MODULE_SW_STANDBY)
+ return aptina_read_i2c_reg(&cam_mod->sd,
+ 1, reg, val);
+
+ return -EFAULT;
+}
+
+/* ======================================================================== */
+
+int aptina_camera_module_init(struct aptina_camera_module *cam_mod,
+ struct aptina_camera_module_custom_config *custom)
+{
+ int ret = 0;
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "\n");
+
+ aptina_camera_module_reset(cam_mod);
+
+ if (IS_ERR_OR_NULL(custom->start_streaming) ||
+ IS_ERR_OR_NULL(custom->stop_streaming) ||
+ IS_ERR_OR_NULL(custom->s_ctrl) ||
+ IS_ERR_OR_NULL(custom->g_ctrl)) {
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "mandatory callback function is missing\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = pltfrm_camera_module_init(&cam_mod->sd, &cam_mod->pltfm_data);
+ if (IS_ERR_VALUE(ret))
+ goto err;
+
+ ret = pltfrm_camera_module_set_pin_state(&cam_mod->sd,
+ PLTFRM_CAMERA_MODULE_PIN_PD,
+ PLTFRM_CAMERA_MODULE_PIN_STATE_INACTIVE);
+ ret = pltfrm_camera_module_set_pin_state(&cam_mod->sd,
+ PLTFRM_CAMERA_MODULE_PIN_RESET,
+ PLTFRM_CAMERA_MODULE_PIN_STATE_ACTIVE);
+ if (IS_ERR_VALUE(ret)) {
+ aptina_camera_module_release(cam_mod);
+ goto err;
+ }
+/*
+ *if (custom->check_camera_id) {
+ * aptina_camera_module_s_power(&cam_mod->sd, 1);
+ * ret = (custom->check_camera_id)(cam_mod);
+ * aptina_camera_module_s_power(&cam_mod->sd, 0);
+ *}
+ *
+ *if (IS_ERR_VALUE(ret)) {
+ * aptina_camera_module_release(cam_mod);
+ * goto err;
+ *}
+ */
+
+ return 0;
+err:
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "failed with error %d\n", ret);
+ return ret;
+}
+
+void aptina_camera_module_release(struct aptina_camera_module *cam_mod)
+{
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "\n");
+
+ cam_mod->custom.configs = NULL;
+
+ pltfrm_camera_module_release(&cam_mod->sd);
+ v4l2_device_unregister_subdev(&cam_mod->sd);
+}
--- /dev/null
+/*
+ * aptina_camera_module.h
+ *
+ * Generic galaxycore sensor driver
+ *
+ * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd.
+ *
+ * Copyright (C) 2012-2014 Intel Mobile Communications GmbH
+ *
+ * Copyright (C) 2008 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+
+#ifndef APTINA_CAMERA_MODULE_H
+#define APTINA_CAMERA_MODULE_H
+#include <linux/workqueue.h>
+#include <linux/platform_data/rk_isp10_platform_camera_module.h>
+#include <linux/platform_data/rk_isp10_platform.h>
+/*
+ * TODO: references to v4l2 should be reomved from here and go into a
+ * platform dependent wrapper
+ */
+
+#define APTINA_CAMERA_MODULE_REG_TYPE_DATA \
+ PLTFRM_CAMERA_MODULE_REG_TYPE_DATA
+#define APTINA_CAMERA_MODULE_REG_TYPE_TIMEOUT \
+ PLTFRM_CAMERA_MODULE_REG_TYPE_TIMEOUT
+#define aptina_camera_module_csi_config
+#define aptina_camera_module_reg pltfrm_camera_module_reg
+#define APTINA_FLIP_BIT_MASK 0x2
+#define APTINA_MIRROR_BIT_MASK 0x1
+
+#define APTINA_CAMERA_MODULE_CTRL_UPDT_GAIN 0x01
+#define APTINA_CAMERA_MODULE_CTRL_UPDT_EXP_TIME 0x02
+#define APTINA_CAMERA_MODULE_CTRL_UPDT_WB_TEMPERATURE 0x04
+#define APTINA_CAMERA_MODULE_CTRL_UPDT_AUTO_WB 0x08
+#define APTINA_CAMERA_MODULE_CTRL_UPDT_AUTO_GAIN 0x10
+#define APTINA_CAMERA_MODULE_CTRL_UPDT_AUTO_EXP 0x20
+#define APTINA_CAMERA_MODULE_CTRL_UPDT_FOCUS_ABSOLUTE 0x40
+#define APTINA_CAMERA_MODULE_CTRL_UPDT_PRESET_WB 0x80
+
+enum aptina_camera_module_state {
+ APTINA_CAMERA_MODULE_POWER_OFF = 0,
+ APTINA_CAMERA_MODULE_HW_STANDBY = 1,
+ APTINA_CAMERA_MODULE_SW_STANDBY = 2,
+ APTINA_CAMERA_MODULE_STREAMING = 3
+};
+
+struct aptina_camera_module;
+
+struct aptina_camera_module_timings {
+ /* public */
+ u32 coarse_integration_time_min;
+ u32 coarse_integration_time_max_margin;
+ u32 fine_integration_time_min;
+ u32 fine_integration_time_max_margin;
+ u32 frame_length_lines;
+ u32 line_length_pck;
+ u32 vt_pix_clk_freq_hz;
+ u32 sensor_output_width;
+ u32 sensor_output_height;
+ u32 crop_horizontal_start; /* Sensor crop start cord. (x0,y0) */
+ u32 crop_vertical_start;
+ u32 crop_horizontal_end; /* Sensor crop end cord. (x1,y1) */
+ u32 crop_vertical_end;
+ u8 binning_factor_x;
+ u8 binning_factor_y;
+};
+
+struct aptina_camera_module_config {
+ const char *name;
+ struct v4l2_mbus_framefmt frm_fmt;
+ struct v4l2_subdev_frame_interval frm_intrvl;
+ bool auto_exp_enabled;
+ bool auto_gain_enabled;
+ bool auto_wb_enabled;
+ struct aptina_camera_module_reg *reg_table;
+ u32 reg_table_num_entries;
+ u32 bayer_order_alter_enble;
+ u32 v_blanking_time_us;
+ u32 line_length_pck;
+ u32 frame_length_lines;
+ struct aptina_camera_module_timings timings;
+ bool soft_reset;
+ bool ignore_measurement_check;
+ struct pltfrm_cam_itf itf_cfg;
+};
+
+struct aptina_camera_module_exp_config {
+ u32 exp_time;
+ bool auto_exp;
+ u16 gain;
+ u16 gain_percent;
+ bool auto_gain;
+ enum v4l2_flash_led_mode flash_mode;
+};
+
+struct aptina_camera_module_wb_config {
+ u32 temperature;
+ u32 preset_id;
+ bool auto_wb;
+};
+
+struct aptina_camera_module_af_config {
+ u32 abs_pos;
+ u32 rel_pos;
+};
+
+struct aptina_camera_module_ext_ctrl {
+ /* public */
+ u32 id;
+ u32 value;
+ __u32 reserved2[1];
+};
+
+struct aptina_camera_module_ext_ctrls {
+ /* public */
+ u32 count;
+ struct aptina_camera_module_ext_ctrl *ctrls;
+};
+
+/*
+ * start_streaming: (mandatory) will be called when sensor should be
+ * put into streaming mode right after the base config has been
+ * written to the sensor. After a successful call of this function
+ * the sensor should start delivering frame data.
+ *
+ * stop_streaming: (mandatory) will be called when sensor should stop
+ * delivering data. After a successful call of this function the
+ * sensor should not deliver any more frame data.
+ *
+ * check_camera_id: (optional) will be called when the sensor is
+ * powered on. If provided should check the sensor ID/version
+ * required by the custom driver. Register access should be
+ * possible when this function is invoked.
+ *
+ * s_ctrl: (mandatory) will be called at the successful end of
+ * aptina_camera_module_s_ctrl with the ctrl_id as argument.
+ *
+ * priv: (optional) for private data used by the custom driver.
+ */
+struct aptina_camera_module_custom_config {
+ int (*start_streaming)(struct aptina_camera_module *cam_mod);
+ int (*stop_streaming)(struct aptina_camera_module *cam_mod);
+ int (*check_camera_id)(struct aptina_camera_module *cam_mod);
+ int (*s_ctrl)(struct aptina_camera_module *cam_mod, u32 ctrl_id);
+ int (*g_ctrl)(struct aptina_camera_module *cam_mod, u32 ctrl_id);
+ int (*g_timings)(struct aptina_camera_module *cam_mod,
+ struct aptina_camera_module_timings *timings);
+ int (*s_ext_ctrls)(struct aptina_camera_module *cam_mod,
+ struct aptina_camera_module_ext_ctrls *ctrls);
+ int (*set_flip)(struct aptina_camera_module *cam_mod);
+ struct aptina_camera_module_config *configs;
+ int (*init_common)(struct aptina_camera_module *cam_mod);
+ int (*g_exposure_valid_frame)(struct aptina_camera_module *cam_mod);
+ u32 num_configs;
+ u32 power_up_delays_ms[3];
+ void *priv;
+ struct aptina_camera_module_timings timings;
+};
+
+struct aptina_camera_module {
+ /* public */
+ struct v4l2_subdev sd;
+ struct v4l2_mbus_framefmt frm_fmt;
+ struct v4l2_subdev_frame_interval frm_intrvl;
+ struct aptina_camera_module_exp_config exp_config;
+ struct aptina_camera_module_wb_config wb_config;
+ struct aptina_camera_module_af_config af_config;
+ struct aptina_camera_module_custom_config custom;
+ enum aptina_camera_module_state state;
+ enum aptina_camera_module_state state_before_suspend;
+ struct aptina_camera_module_config *active_config;
+ u32 ctrl_updt;
+ u32 vts_min;
+ bool auto_adjust_fps;
+ bool update_config;
+ bool frm_fmt_valid;
+ bool frm_intrvl_valid;
+ bool hflip;
+ bool vflip;
+ u32 rotation;
+ void *pltfm_data;
+ bool inited;
+};
+
+#define aptina_camera_module_pr_info(cam_mod, fmt, arg...) \
+ pltfrm_camera_module_pr_info(&cam_mod->sd, fmt, ## arg)
+#define aptina_camera_module_pr_debug(cam_mod, fmt, arg...) \
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, fmt, ## arg)
+#define aptina_camera_module_pr_warn(cam_mod, fmt, arg...) \
+ pltfrm_camera_module_pr_warn(&cam_mod->sd, fmt, ## arg)
+#define aptina_camera_module_pr_err(cam_mod, fmt, arg...) \
+ pltfrm_camera_module_pr_err(&cam_mod->sd, fmt, ## arg)
+
+int aptina_camera_module_write_reglist(
+ struct aptina_camera_module *cam_mod,
+ const struct aptina_camera_module_reg reglist[],
+ int len);
+
+int aptina_camera_module_write_reg(
+ struct aptina_camera_module *cam_mod,
+ u16 reg,
+ u16 val);
+
+int aptina_camera_module_read_reg(
+ struct aptina_camera_module *cam_mod,
+ u16 data_length,
+ u16 reg,
+ u32 *val);
+
+int aptina_camera_module_read_reg_table(
+ struct aptina_camera_module *cam_mod,
+ u16 reg,
+ u32 *val);
+
+int aptina_camera_module_try_fmt(
+ struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *fmt);
+
+int aptina_camera_module_s_fmt(
+ struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format);
+
+int aptina_camera_module_g_fmt(
+ struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format);
+
+int aptina_camera_module_s_frame_interval(
+ struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *interval);
+
+int aptina_camera_module_s_stream(
+ struct v4l2_subdev *sd,
+ int enable);
+
+int aptina_camera_module_s_power(
+ struct v4l2_subdev *sd,
+ int on);
+
+int aptina_camera_module_g_ctrl(
+ struct v4l2_subdev *sd,
+ struct v4l2_control *ctrl);
+
+int aptina_camera_module_s_ctrl(
+ struct v4l2_subdev *sd,
+ struct v4l2_control *ctrl);
+
+int aptina_camera_module_s_ext_ctrls(
+ struct v4l2_subdev *sd,
+ struct v4l2_ext_controls *ctrls);
+
+int aptina_camera_module_enum_frameintervals(
+ struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_interval_enum *file);
+
+int aptina_camera_module_init(
+ struct aptina_camera_module *cam_mod,
+ struct aptina_camera_module_custom_config *custom);
+
+void aptina_camera_module_release(
+ struct aptina_camera_module *cam_mod);
+
+long aptina_camera_module_ioctl(struct v4l2_subdev *sd,
+ unsigned int cmd,
+ void *arg);
+
+int aptina_camera_module_get_flip_mirror(
+ struct aptina_camera_module *cam_mod);
+#endif
+
--- /dev/null
+/*
+ * IMX323 sensor driver
+ *
+ * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd.
+ *
+ * Copyright (C) 2012-2014 Intel Mobile Communications GmbH
+ *
+ * Copyright (C) 2008 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <media/v4l2-subdev.h>
+#include <media/videobuf-core.h>
+#include <linux/slab.h>
+#include "imx_camera_module.h"
+
+#define IMX323_DRIVER_NAME "imx323"
+
+#define IMX323_AEC_PK_GAIN_REG 0x301e
+
+#define IMX323_AEC_PK_EXPO_HIGH_REG 0x0202
+#define IMX323_AEC_PK_EXPO_LOW_REG 0x0203
+
+#define IMX323_FETCH_HIGH_BYTE_EXP(VAL) ((VAL >> 8) & 0xFF)
+#define IMX323_FETCH_LOW_BYTE_EXP(VAL) (VAL & 0xFF)
+
+#define IMX323_PID_ADDR 0x0112
+#define IMX323_PID_MAGIC 0xa
+
+#define IMX323_TIMING_VTS_HIGH_REG 0x0340
+#define IMX323_TIMING_VTS_LOW_REG 0x0341
+#define IMX323_TIMING_HTS_HIGH_REG 0x0342
+#define IMX323_TIMING_HTS_LOW_REG 0x0343
+
+#define IMX323_INTEGRATION_TIME_MARGIN 8
+#define IMX323_FINE_INTG_TIME_MIN 0
+#define IMX323_FINE_INTG_TIME_MAX_MARGIN 0
+#define IMX323_COARSE_INTG_TIME_MIN 16
+#define IMX323_COARSE_INTG_TIME_MAX_MARGIN 4
+
+#define IMX323_ORIENTATION_REG 0x0101
+#define IMX323_ORIENTATION_H 0x1
+#define IMX323_ORIENTATION_V 0x2
+
+#define IMX323_EXT_CLK 37125000
+
+static struct imx_camera_module imx323;
+static struct imx_camera_module_custom_config imx323_custom_config;
+
+/* ======================================================================== */
+/* Base sensor configs */
+/* ======================================================================== */
+
+/* MCLK:37.125MHz 1920x1080 30fps DVP_12_DATA PCLK:74.25MHz */
+static struct imx_camera_module_reg imx323_init_tab_1920_1080_30fps[] = {
+ {IMX_CAMERA_MODULE_REG_TYPE_DATA, 0x0100, 0x00},
+ {IMX_CAMERA_MODULE_REG_TYPE_TIMEOUT, 0x0000, 0x01},
+ {IMX_CAMERA_MODULE_REG_TYPE_DATA, 0x0009, 0xf0},
+ {IMX_CAMERA_MODULE_REG_TYPE_DATA, 0x0112, 0x0c},
+ {IMX_CAMERA_MODULE_REG_TYPE_DATA, 0x0113, 0x0c},
+ {IMX_CAMERA_MODULE_REG_TYPE_DATA, 0x0340, 0x04},
+ {IMX_CAMERA_MODULE_REG_TYPE_DATA, 0x0341, 0x65},
+ {IMX_CAMERA_MODULE_REG_TYPE_DATA, 0x0342, 0x04},
+ {IMX_CAMERA_MODULE_REG_TYPE_DATA, 0x0343, 0x4c},
+ {IMX_CAMERA_MODULE_REG_TYPE_TIMEOUT, 0x0000, 0x01},
+ {IMX_CAMERA_MODULE_REG_TYPE_DATA, 0x3000, 0x31},
+ {IMX_CAMERA_MODULE_REG_TYPE_DATA, 0x3002, 0x0f},
+ {IMX_CAMERA_MODULE_REG_TYPE_DATA, 0x3011, 0x00},
+ {IMX_CAMERA_MODULE_REG_TYPE_DATA, 0x3012, 0x82},
+ {IMX_CAMERA_MODULE_REG_TYPE_DATA, 0x3013, 0x40},
+ {IMX_CAMERA_MODULE_REG_TYPE_DATA, 0x3016, 0x3c},
+ {IMX_CAMERA_MODULE_REG_TYPE_DATA, 0x301a, 0xc9},
+ {IMX_CAMERA_MODULE_REG_TYPE_DATA, 0x301c, 0x50},
+ {IMX_CAMERA_MODULE_REG_TYPE_DATA, 0x301f, 0x73},
+ {IMX_CAMERA_MODULE_REG_TYPE_DATA, 0x3021, 0x00},
+ {IMX_CAMERA_MODULE_REG_TYPE_DATA, 0x3022, 0x40},
+ {IMX_CAMERA_MODULE_REG_TYPE_TIMEOUT, 0x0000, 0x01},
+ {IMX_CAMERA_MODULE_REG_TYPE_DATA, 0x3027, 0x20},
+ {IMX_CAMERA_MODULE_REG_TYPE_DATA, 0x302c, 0x00},
+ {IMX_CAMERA_MODULE_REG_TYPE_DATA, 0x303f, 0x0a},
+ {IMX_CAMERA_MODULE_REG_TYPE_DATA, 0x304f, 0x47},
+ {IMX_CAMERA_MODULE_REG_TYPE_DATA, 0x3054, 0x11},
+ {IMX_CAMERA_MODULE_REG_TYPE_DATA, 0x307a, 0x00},
+ {IMX_CAMERA_MODULE_REG_TYPE_DATA, 0x307b, 0x00},
+ {IMX_CAMERA_MODULE_REG_TYPE_DATA, 0x3098, 0x26},
+ {IMX_CAMERA_MODULE_REG_TYPE_DATA, 0x3099, 0x02},
+ {IMX_CAMERA_MODULE_REG_TYPE_DATA, 0x309a, 0x26},
+ {IMX_CAMERA_MODULE_REG_TYPE_DATA, 0x309b, 0x02},
+ {IMX_CAMERA_MODULE_REG_TYPE_DATA, 0x30ce, 0x16},
+ {IMX_CAMERA_MODULE_REG_TYPE_DATA, 0x30cf, 0x82},
+ {IMX_CAMERA_MODULE_REG_TYPE_DATA, 0x30d0, 0x00},
+ {IMX_CAMERA_MODULE_REG_TYPE_DATA, 0x3117, 0x0d}
+};
+
+/* ======================================================================== */
+
+static struct imx_camera_module_config imx323_configs[] = {
+ {
+ .name = "1920x1080_30fps",
+ .frm_fmt = {
+ .width = 2200,
+ .height = 1125,
+ .code = MEDIA_BUS_FMT_SGBRG12_1X12
+ },
+ .frm_intrvl = {
+ .interval = {
+ .numerator = 1,
+ .denominator = 30
+ }
+ },
+ .auto_exp_enabled = false,
+ .auto_gain_enabled = false,
+ .auto_wb_enabled = false,
+ .reg_table = (void *)imx323_init_tab_1920_1080_30fps,
+ .reg_table_num_entries =
+ sizeof(imx323_init_tab_1920_1080_30fps) /
+ sizeof(imx323_init_tab_1920_1080_30fps[0]),
+ .v_blanking_time_us = 5000,
+ PLTFRM_CAM_ITF_DVP_CFG(
+ PLTFRM_CAM_ITF_BT601_12,
+ PLTFRM_CAM_SIGNAL_HIGH_LEVEL,
+ PLTFRM_CAM_SIGNAL_HIGH_LEVEL,
+ PLTFRM_CAM_SDR_NEG_EDG,
+ IMX323_EXT_CLK)
+ }
+};
+
+/*--------------------------------------------------------------------------*/
+
+static int imx323_g_VTS(struct imx_camera_module *cam_mod, u32 *vts)
+{
+ u32 msb, lsb;
+ int ret;
+
+ ret = imx_camera_module_read_reg_table(
+ cam_mod,
+ IMX323_TIMING_VTS_HIGH_REG,
+ &msb);
+ if (IS_ERR_VALUE(ret))
+ goto err;
+
+ ret = imx_camera_module_read_reg_table(
+ cam_mod,
+ IMX323_TIMING_VTS_LOW_REG,
+ &lsb);
+ if (IS_ERR_VALUE(ret))
+ goto err;
+
+ *vts = (msb << 8) | lsb;
+
+ return 0;
+err:
+ imx_camera_module_pr_err(cam_mod, "failed with error (%d)\n", ret);
+ return ret;
+}
+
+/*--------------------------------------------------------------------------*/
+
+static int imx323_auto_adjust_fps(struct imx_camera_module *cam_mod,
+ u32 exp_time)
+{
+ int ret;
+ u32 vts;
+
+ if ((cam_mod->exp_config.exp_time + IMX323_COARSE_INTG_TIME_MAX_MARGIN)
+ > cam_mod->vts_min)
+ vts = cam_mod->exp_config.exp_time +
+ IMX323_COARSE_INTG_TIME_MAX_MARGIN;
+ else
+ vts = cam_mod->vts_min;
+ ret = imx_camera_module_write_reg(cam_mod,
+ IMX323_TIMING_VTS_LOW_REG, vts & 0xFF);
+ ret |= imx_camera_module_write_reg(cam_mod,
+ IMX323_TIMING_VTS_HIGH_REG, (vts >> 8) & 0xFF);
+
+ if (IS_ERR_VALUE(ret))
+ imx_camera_module_pr_err(cam_mod,
+ "failed with error (%d)\n", ret);
+ else
+ imx_camera_module_pr_debug(cam_mod,
+ "updated vts = %d,vts_min=%d\n", vts, cam_mod->vts_min);
+
+ return ret;
+}
+
+/*--------------------------------------------------------------------------*/
+
+static int imx323_write_aec(struct imx_camera_module *cam_mod)
+{
+ int ret = 0;
+
+ imx_camera_module_pr_debug(cam_mod,
+ "exp_time = %d, gain = %d, flash_mode = %d\n",
+ cam_mod->exp_config.exp_time,
+ cam_mod->exp_config.gain,
+ cam_mod->exp_config.flash_mode);
+
+ /*
+ * if the sensor is already streaming, write to shadow registers,
+ * if the sensor is in SW standby, write to active registers,
+ * if the sensor is off/registers are not writeable, do nothing
+ */
+ if ((cam_mod->state == IMX_CAMERA_MODULE_SW_STANDBY) ||
+ (cam_mod->state == IMX_CAMERA_MODULE_STREAMING)) {
+ u32 a_gain = cam_mod->exp_config.gain;
+ u32 exp_time = cam_mod->exp_config.exp_time;
+
+ a_gain = a_gain * cam_mod->exp_config.gain_percent / 100;
+
+ if (!IS_ERR_VALUE(ret) && cam_mod->auto_adjust_fps)
+ ret = imx323_auto_adjust_fps(cam_mod,
+ cam_mod->exp_config.exp_time);
+
+ /* Gain */
+ ret = imx_camera_module_write_reg(cam_mod,
+ IMX323_AEC_PK_GAIN_REG, a_gain);
+
+ /* Integration Time */
+ ret = imx_camera_module_write_reg(cam_mod,
+ IMX323_AEC_PK_EXPO_HIGH_REG,
+ IMX323_FETCH_HIGH_BYTE_EXP(exp_time));
+ ret |= imx_camera_module_write_reg(cam_mod,
+ IMX323_AEC_PK_EXPO_LOW_REG,
+ IMX323_FETCH_LOW_BYTE_EXP(exp_time));
+ }
+
+ if (IS_ERR_VALUE(ret))
+ imx_camera_module_pr_err(cam_mod,
+ "failed with error (%d)\n", ret);
+ return ret;
+}
+
+/*--------------------------------------------------------------------------*/
+
+static int imx323_g_ctrl(struct imx_camera_module *cam_mod, u32 ctrl_id)
+{
+ int ret = 0;
+
+ imx_camera_module_pr_debug(cam_mod, "\n");
+
+ switch (ctrl_id) {
+ case V4L2_CID_GAIN:
+ case V4L2_CID_EXPOSURE:
+ case V4L2_CID_FLASH_LED_MODE:
+ /* nothing to be done here */
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ if (IS_ERR_VALUE(ret))
+ imx_camera_module_pr_debug(cam_mod,
+ "failed with error (%d)\n", ret);
+ return ret;
+}
+
+/*--------------------------------------------------------------------------*/
+
+static int imx323_filltimings(struct imx_camera_module_custom_config *custom)
+{
+ int i, j;
+ struct imx_camera_module_config *config;
+ struct imx_camera_module_timings *timings;
+ struct imx_camera_module_reg *reg_table;
+ int reg_table_num_entries;
+
+ for (i = 0; i < custom->num_configs; i++) {
+ config = &custom->configs[i];
+ reg_table = config->reg_table;
+ reg_table_num_entries = config->reg_table_num_entries;
+ timings = &config->timings;
+
+ for (j = 0; j < reg_table_num_entries; j++) {
+ switch (reg_table[j].reg) {
+ case IMX323_TIMING_VTS_HIGH_REG:
+ timings->frame_length_lines =
+ reg_table[j].val << 8;
+ break;
+ case IMX323_TIMING_VTS_LOW_REG:
+ timings->frame_length_lines |= reg_table[j].val;
+ break;
+ case IMX323_TIMING_HTS_HIGH_REG:
+ timings->line_length_pck =
+ (reg_table[j].val << 8);
+ break;
+ case IMX323_TIMING_HTS_LOW_REG:
+ timings->line_length_pck |= reg_table[j].val;
+ break;
+ }
+ }
+
+ timings->exp_time >>= 4;
+ timings->line_length_pck = timings->line_length_pck * 2;
+ timings->vt_pix_clk_freq_hz =
+ config->frm_intrvl.interval.denominator
+ * timings->frame_length_lines
+ * timings->line_length_pck;
+
+ timings->coarse_integration_time_min =
+ IMX323_COARSE_INTG_TIME_MIN;
+ timings->coarse_integration_time_max_margin =
+ IMX323_COARSE_INTG_TIME_MAX_MARGIN;
+
+ /* IMX Sensor do not use fine integration time. */
+ timings->fine_integration_time_min = IMX323_FINE_INTG_TIME_MIN;
+ timings->fine_integration_time_max_margin =
+ IMX323_FINE_INTG_TIME_MAX_MARGIN;
+ }
+
+ return 0;
+}
+
+static int imx323_g_timings(struct imx_camera_module *cam_mod,
+ struct imx_camera_module_timings *timings)
+{
+ int ret = 0;
+ unsigned int vts;
+
+ if (IS_ERR_OR_NULL(cam_mod->active_config))
+ goto err;
+
+ *timings = cam_mod->active_config->timings;
+
+ vts = (!cam_mod->vts_cur) ?
+ timings->frame_length_lines :
+ cam_mod->vts_cur;
+
+ if (cam_mod->frm_intrvl_valid)
+ timings->vt_pix_clk_freq_hz =
+ cam_mod->frm_intrvl.interval.denominator
+ * vts
+ * timings->line_length_pck;
+ else
+ timings->vt_pix_clk_freq_hz =
+ cam_mod->active_config->frm_intrvl.interval.denominator
+ * vts
+ * timings->line_length_pck;
+
+ return ret;
+err:
+ imx_camera_module_pr_err(cam_mod, "failed with error (%d)\n", ret);
+ return ret;
+}
+
+/*--------------------------------------------------------------------------*/
+
+static int imx323_set_flip(struct imx_camera_module *cam_mod)
+{
+ int mode = 0;
+ u16 orientation = 0;
+
+ mode = imx_camera_module_get_flip_mirror(cam_mod);
+ if (mode == -1) {
+ imx_camera_module_pr_info(cam_mod,
+ "dts don't set flip, return!\n");
+ return 0;
+ }
+
+ if (!IS_ERR_OR_NULL(cam_mod->active_config)) {
+ if (mode == IMX_FLIP_BIT_MASK)
+ orientation = IMX323_ORIENTATION_V;
+ else if (mode == IMX_MIRROR_BIT_MASK)
+ orientation = IMX323_ORIENTATION_H;
+ else if (mode == (IMX_MIRROR_BIT_MASK | IMX_FLIP_BIT_MASK))
+ orientation = IMX323_ORIENTATION_H |
+ IMX323_ORIENTATION_V;
+ else
+ orientation = 0;
+ }
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+static int imx323_s_ctrl(struct imx_camera_module *cam_mod, u32 ctrl_id)
+{
+ int ret = 0;
+
+ imx_camera_module_pr_debug(cam_mod, "\n");
+
+ switch (ctrl_id) {
+ case V4L2_CID_GAIN:
+ case V4L2_CID_EXPOSURE:
+ ret = imx323_write_aec(cam_mod);
+ break;
+ case V4L2_CID_FLASH_LED_MODE:
+ /* nothing to be done here */
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ if (IS_ERR_VALUE(ret))
+ imx_camera_module_pr_debug(cam_mod,
+ "failed with error (%d) 0x%x\n",
+ ret, ctrl_id);
+ return ret;
+}
+
+/*--------------------------------------------------------------------------*/
+
+static int imx323_s_ext_ctrls(struct imx_camera_module *cam_mod,
+ struct imx_camera_module_ext_ctrls *ctrls)
+{
+ int ret = 0;
+
+ /* Handles only exposure and gain together special case. */
+ if (ctrls->count == 1)
+ ret = imx323_s_ctrl(cam_mod, ctrls->ctrls[0].id);
+ else if ((ctrls->count == 3) &&
+ ((ctrls->ctrls[0].id == V4L2_CID_GAIN &&
+ ctrls->ctrls[1].id == V4L2_CID_EXPOSURE) ||
+ (ctrls->ctrls[1].id == V4L2_CID_GAIN &&
+ ctrls->ctrls[0].id == V4L2_CID_EXPOSURE)))
+ ret = imx323_write_aec(cam_mod);
+ else
+ ret = -EINVAL;
+
+ if (IS_ERR_VALUE(ret))
+ imx_camera_module_pr_debug(cam_mod,
+ "failed with error (%d)\n", ret);
+ return ret;
+}
+
+/*--------------------------------------------------------------------------*/
+
+static int imx323_start_streaming(struct imx_camera_module *cam_mod)
+{
+ int ret = 0;
+
+ imx_camera_module_pr_debug(cam_mod,
+ "active config=%s\n", cam_mod->active_config->name);
+
+ ret = imx323_g_VTS(cam_mod, &cam_mod->vts_min);
+ if (IS_ERR_VALUE(ret))
+ goto err;
+
+ if (IS_ERR_VALUE(imx_camera_module_write_reg(cam_mod, 0x0100, 1)))
+ goto err;
+
+ msleep(25);
+
+ return 0;
+err:
+ imx_camera_module_pr_err(cam_mod, "failed with error (%d)\n",
+ ret);
+ return ret;
+}
+
+/*--------------------------------------------------------------------------*/
+
+static int imx323_stop_streaming(struct imx_camera_module *cam_mod)
+{
+ int ret = 0;
+
+ imx_camera_module_pr_debug(cam_mod, "\n");
+
+ ret = imx_camera_module_write_reg(cam_mod, 0x0100, 0);
+ if (IS_ERR_VALUE(ret))
+ goto err;
+
+ msleep(25);
+
+ return 0;
+err:
+ imx_camera_module_pr_err(cam_mod, "failed with error (%d)\n", ret);
+ return ret;
+}
+
+/*--------------------------------------------------------------------------*/
+static int imx323_check_camera_id(struct imx_camera_module *cam_mod)
+{
+ u32 pid;
+ int ret = 0;
+
+ imx_camera_module_pr_debug(cam_mod, "\n");
+
+ ret |= imx_camera_module_read_reg(cam_mod, 1, IMX323_PID_ADDR, &pid);
+ if (IS_ERR_VALUE(ret)) {
+ imx_camera_module_pr_err(cam_mod,
+ "register read failed, camera module powered off?\n");
+ goto err;
+ }
+
+ if (pid == IMX323_PID_MAGIC) {
+ imx_camera_module_pr_debug(cam_mod,
+ "successfully detected camera ID 0x%02x\n",
+ pid);
+ } else {
+ imx_camera_module_pr_err(cam_mod,
+ "wrong camera ID, expected 0x%02x, detected 0x%02x\n",
+ IMX323_PID_MAGIC, pid);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ return 0;
+err:
+ imx_camera_module_pr_err(cam_mod, "failed with error (%d)\n", ret);
+ return ret;
+}
+
+/* ======================================================================== */
+/* This part is platform dependent */
+/* ======================================================================== */
+
+static struct v4l2_subdev_core_ops imx323_camera_module_core_ops = {
+ .g_ctrl = imx_camera_module_g_ctrl,
+ .s_ctrl = imx_camera_module_s_ctrl,
+ .s_ext_ctrls = imx_camera_module_s_ext_ctrls,
+ .s_power = imx_camera_module_s_power,
+ .ioctl = imx_camera_module_ioctl
+};
+
+static struct v4l2_subdev_video_ops imx323_camera_module_video_ops = {
+ .s_frame_interval = imx_camera_module_s_frame_interval,
+ .s_stream = imx_camera_module_s_stream
+};
+
+static struct v4l2_subdev_pad_ops imx323_camera_module_pad_ops = {
+ .enum_frame_interval = imx_camera_module_enum_frameintervals,
+ .get_fmt = imx_camera_module_g_fmt,
+ .set_fmt = imx_camera_module_s_fmt,
+};
+
+static struct v4l2_subdev_ops imx323_camera_module_ops = {
+ .core = &imx323_camera_module_core_ops,
+ .video = &imx323_camera_module_video_ops,
+ .pad = &imx323_camera_module_pad_ops
+};
+
+static struct imx_camera_module_custom_config imx323_custom_config = {
+ .start_streaming = imx323_start_streaming,
+ .stop_streaming = imx323_stop_streaming,
+ .s_ctrl = imx323_s_ctrl,
+ .s_ext_ctrls = imx323_s_ext_ctrls,
+ .g_ctrl = imx323_g_ctrl,
+ .g_timings = imx323_g_timings,
+ .check_camera_id = imx323_check_camera_id,
+ .set_flip = imx323_set_flip,
+ .configs = imx323_configs,
+ .num_configs = ARRAY_SIZE(imx323_configs),
+ .power_up_delays_ms = {5, 20, 0}
+};
+
+static int imx323_probe(
+ struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ dev_info(&client->dev, "probing...\n");
+
+ imx323_filltimings(&imx323_custom_config);
+ v4l2_i2c_subdev_init(&imx323.sd, client, &imx323_camera_module_ops);
+ imx323.custom = imx323_custom_config;
+
+ dev_info(&client->dev, "probing successful\n");
+ return 0;
+}
+
+static int imx323_remove(struct i2c_client *client)
+{
+ struct imx_camera_module *cam_mod = i2c_get_clientdata(client);
+
+ dev_info(&client->dev, "removing device...\n");
+
+ if (!client->adapter)
+ return -ENODEV; /* our client isn't attached */
+
+ imx_camera_module_release(cam_mod);
+
+ dev_info(&client->dev, "removed\n");
+ return 0;
+}
+
+static const struct i2c_device_id imx323_id[] = {
+ { IMX323_DRIVER_NAME, 0 },
+ { }
+};
+
+static const struct of_device_id imx323_of_match[] = {
+ {.compatible = "sony,imx323-v4l2-i2c-subdev"},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, imx323_id);
+
+static struct i2c_driver imx323_i2c_driver = {
+ .driver = {
+ .name = IMX323_DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = imx323_of_match
+ },
+ .probe = imx323_probe,
+ .remove = imx323_remove,
+ .id_table = imx323_id,
+};
+
+module_i2c_driver(imx323_i2c_driver);
+
+MODULE_DESCRIPTION("SoC Camera driver for IMX323");
+MODULE_AUTHOR("George");
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * imx_camera_module.c
+ *
+ * Generic sony sensor driver
+ *
+ * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd.
+ *
+ * Copyright (C) 2012-2014 Intel Mobile Communications GmbH
+ *
+ * Copyright (C) 2008 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+
+#include <linux/delay.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-device.h>
+#include <media/videobuf-core.h>
+#include <linux/slab.h>
+#include <linux/gcd.h>
+#include <media/v4l2-controls_rockchip.h>
+
+#include "imx_camera_module.h"
+
+static struct imx_camera_module *to_imx_camera_module(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct imx_camera_module, sd);
+}
+
+/* ======================================================================== */
+
+static void imx_camera_module_reset(
+ struct imx_camera_module *cam_mod)
+{
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "\n");
+
+ cam_mod->inited = false;
+ cam_mod->active_config = NULL;
+ cam_mod->update_config = true;
+ cam_mod->frm_fmt_valid = false;
+ cam_mod->frm_intrvl_valid = false;
+ cam_mod->exp_config.auto_exp = false;
+ cam_mod->exp_config.auto_gain = false;
+ cam_mod->wb_config.auto_wb = false;
+ cam_mod->hflip = false;
+ cam_mod->vflip = false;
+ cam_mod->auto_adjust_fps = true;
+ cam_mod->rotation = 0;
+ cam_mod->ctrl_updt = 0;
+ cam_mod->state = IMX_CAMERA_MODULE_POWER_OFF;
+ cam_mod->state_before_suspend = IMX_CAMERA_MODULE_POWER_OFF;
+ cam_mod->exp_config.exp_time = 0;
+ cam_mod->exp_config.gain = 0;
+ cam_mod->vts_cur = 0;
+}
+
+/* ======================================================================== */
+
+static void imx_camera_module_set_active_config(
+ struct imx_camera_module *cam_mod,
+ struct imx_camera_module_config *new_config)
+{
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "\n");
+
+ if (IS_ERR_OR_NULL(new_config)) {
+ cam_mod->active_config = new_config;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "no active config\n");
+ } else {
+ cam_mod->ctrl_updt &= IMX_CAMERA_MODULE_CTRL_UPDT_AUTO_EXP |
+ IMX_CAMERA_MODULE_CTRL_UPDT_AUTO_GAIN |
+ IMX_CAMERA_MODULE_CTRL_UPDT_AUTO_WB;
+ if (new_config->auto_exp_enabled !=
+ cam_mod->exp_config.auto_exp) {
+ cam_mod->ctrl_updt |=
+ IMX_CAMERA_MODULE_CTRL_UPDT_AUTO_EXP;
+ cam_mod->exp_config.auto_exp =
+ new_config->auto_exp_enabled;
+ }
+ if (new_config->auto_gain_enabled !=
+ cam_mod->exp_config.auto_gain) {
+ cam_mod->ctrl_updt |=
+ IMX_CAMERA_MODULE_CTRL_UPDT_AUTO_GAIN;
+ cam_mod->exp_config.auto_gain =
+ new_config->auto_gain_enabled;
+ }
+ if (new_config->auto_wb_enabled !=
+ cam_mod->wb_config.auto_wb) {
+ cam_mod->ctrl_updt |=
+ IMX_CAMERA_MODULE_CTRL_UPDT_AUTO_WB;
+ cam_mod->wb_config.auto_wb =
+ new_config->auto_wb_enabled;
+ }
+ if (new_config != cam_mod->active_config) {
+ cam_mod->update_config = true;
+ cam_mod->active_config = new_config;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "activating config '%s'\n",
+ cam_mod->active_config->name);
+ }
+ }
+}
+
+/* ======================================================================== */
+
+static struct imx_camera_module_config *imx_camera_module_find_config(
+ struct imx_camera_module *cam_mod,
+ struct v4l2_mbus_framefmt *fmt,
+ struct v4l2_subdev_frame_interval *frm_intrvl)
+{
+ u32 i;
+ unsigned long gcdiv;
+ struct v4l2_subdev_frame_interval norm_interval;
+
+ if (!IS_ERR_OR_NULL(fmt))
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "%dx%d, fmt code 0x%04x\n",
+ fmt->width, fmt->height, fmt->code);
+
+ if (!IS_ERR_OR_NULL(frm_intrvl))
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "frame interval %d/%d\n",
+ frm_intrvl->interval.numerator,
+ frm_intrvl->interval.denominator);
+
+ for (i = 0; i < cam_mod->custom.num_configs; i++) {
+ if (!IS_ERR_OR_NULL(frm_intrvl)) {
+ gcdiv = gcd(cam_mod->custom.configs[i].
+ frm_intrvl.interval.numerator,
+ cam_mod->custom.configs[i].
+ frm_intrvl.interval.denominator);
+ norm_interval.interval.numerator =
+ cam_mod->custom.configs[i].
+ frm_intrvl.interval.numerator / gcdiv;
+ norm_interval.interval.denominator =
+ cam_mod->custom.configs[i].
+ frm_intrvl.interval.denominator / gcdiv;
+ if ((frm_intrvl->interval.numerator !=
+ norm_interval.interval.numerator) ||
+ (frm_intrvl->interval.denominator !=
+ norm_interval.interval.denominator))
+ continue;
+ }
+ if (!IS_ERR_OR_NULL(fmt)) {
+ if ((cam_mod->custom.configs[i].frm_fmt.width !=
+ fmt->width) ||
+ (cam_mod->custom.configs[i].frm_fmt.height !=
+ fmt->height) ||
+ (cam_mod->custom.configs[i].frm_fmt.code !=
+ fmt->code)) {
+ continue;
+ }
+ }
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "found matching config %s\n",
+ cam_mod->custom.configs[i].name);
+ return &cam_mod->custom.configs[i];
+ }
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "no matching config found\n");
+
+ return ERR_PTR(-EINVAL);
+}
+
+/* ======================================================================== */
+
+static int imx_camera_module_write_config(
+ struct imx_camera_module *cam_mod)
+{
+ int ret = 0;
+ struct imx_camera_module_reg *reg_table;
+ u32 reg_table_num_entries;
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "\n");
+
+ if (IS_ERR_OR_NULL(cam_mod->active_config)) {
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "no active sensor configuration");
+ ret = -EFAULT;
+ goto err;
+ }
+
+ if (cam_mod->inited == false) {
+ cam_mod->active_config->soft_reset = true;
+ reg_table = cam_mod->active_config->reg_table;
+ reg_table_num_entries =
+ cam_mod->active_config->reg_table_num_entries;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "write config %s\n",
+ cam_mod->active_config->name);
+ }
+
+ if (!IS_ERR_OR_NULL(cam_mod->custom.set_flip))
+ cam_mod->custom.set_flip(cam_mod);
+
+ ret = pltfrm_camera_module_write_reglist(&cam_mod->sd,
+ reg_table, reg_table_num_entries);
+
+ if (IS_ERR_VALUE(ret))
+ goto err;
+ ret = pltfrm_camera_module_patch_config(&cam_mod->sd,
+ &cam_mod->frm_fmt,
+ &cam_mod->frm_intrvl);
+ if (IS_ERR_VALUE(ret))
+ goto err;
+
+ return 0;
+err:
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "failed with error %d\n", ret);
+ return ret;
+}
+
+static int imx_camera_module_attach(
+ struct imx_camera_module *cam_mod)
+{
+ int ret = 0;
+ struct imx_camera_module_custom_config *custom;
+
+ custom = &cam_mod->custom;
+
+ if (custom->check_camera_id) {
+ imx_camera_module_s_power(&cam_mod->sd, 1);
+ ret = custom->check_camera_id(cam_mod);
+ imx_camera_module_s_power(&cam_mod->sd, 0);
+ if (ret != 0)
+ goto err;
+ }
+
+ return 0;
+err:
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "failed with error %d\n", ret);
+ imx_camera_module_release(cam_mod);
+ return ret;
+}
+
+/* ======================================================================== */
+
+int imx_camera_module_try_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *fmt)
+{
+ struct imx_camera_module *cam_mod = to_imx_camera_module(sd);
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "%dx%d, fmt code 0x%04x\n",
+ fmt->width, fmt->height, fmt->code);
+
+ if (IS_ERR_OR_NULL(imx_camera_module_find_config(cam_mod, fmt, NULL))) {
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "format not supported\n");
+ return -EINVAL;
+ }
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "format supported\n");
+
+ return 0;
+}
+
+/* ======================================================================== */
+
+int imx_camera_module_s_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format)
+{
+ struct imx_camera_module *cam_mod = to_imx_camera_module(sd);
+ struct v4l2_mbus_framefmt *fmt = &format->format;
+ int ret = 0;
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "%dx%d, fmt code 0x%04x\n",
+ fmt->width, fmt->height, fmt->code);
+
+ if (IS_ERR_OR_NULL(imx_camera_module_find_config(cam_mod, fmt, NULL))) {
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "format %dx%d, code 0x%04x, not supported\n",
+ fmt->width, fmt->height, fmt->code);
+ ret = -EINVAL;
+ goto err;
+ }
+ cam_mod->frm_fmt_valid = true;
+ cam_mod->frm_fmt = *fmt;
+ if (cam_mod->frm_intrvl_valid) {
+ imx_camera_module_set_active_config(cam_mod,
+ imx_camera_module_find_config(cam_mod,
+ fmt, &cam_mod->frm_intrvl));
+ }
+ return 0;
+err:
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "failed with error %d\n", ret);
+ return ret;
+}
+
+/* ======================================================================== */
+
+int imx_camera_module_g_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format)
+{
+ struct imx_camera_module *cam_mod = to_imx_camera_module(sd);
+ struct v4l2_mbus_framefmt *fmt = &format->format;
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "\n");
+
+ if (cam_mod->active_config) {
+ fmt->code = cam_mod->active_config->frm_fmt.code;
+ fmt->width = cam_mod->active_config->frm_fmt.width;
+ fmt->height = cam_mod->active_config->frm_fmt.height;
+ return 0;
+ }
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "no active config\n");
+
+ return -1;
+}
+
+/* ======================================================================== */
+
+int imx_camera_module_s_frame_interval(
+ struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *interval)
+{
+ struct imx_camera_module *cam_mod = to_imx_camera_module(sd);
+ unsigned long gcdiv;
+ struct v4l2_subdev_frame_interval norm_interval;
+ int ret = 0;
+
+ if ((interval->interval.denominator == 0) ||
+ (interval->interval.numerator == 0)) {
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "invalid frame interval %d/%d\n",
+ interval->interval.numerator,
+ interval->interval.denominator);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "%d/%d (%dfps)\n",
+ interval->interval.numerator, interval->interval.denominator,
+ (interval->interval.denominator +
+ (interval->interval.numerator >> 1)) /
+ interval->interval.numerator);
+
+ /* normalize interval */
+ gcdiv = gcd(interval->interval.numerator,
+ interval->interval.denominator);
+ norm_interval.interval.numerator =
+ interval->interval.numerator / gcdiv;
+ norm_interval.interval.denominator =
+ interval->interval.denominator / gcdiv;
+
+ if (IS_ERR_OR_NULL(imx_camera_module_find_config(cam_mod,
+ NULL, &norm_interval))) {
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "frame interval %d/%d not supported\n",
+ interval->interval.numerator,
+ interval->interval.denominator);
+ ret = -EINVAL;
+ goto err;
+ }
+ cam_mod->frm_intrvl_valid = true;
+ cam_mod->frm_intrvl = norm_interval;
+ if (cam_mod->frm_fmt_valid) {
+ imx_camera_module_set_active_config(cam_mod,
+ imx_camera_module_find_config(cam_mod,
+ &cam_mod->frm_fmt, interval));
+ }
+ return 0;
+err:
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "failed with error %d\n", ret);
+ return ret;
+}
+
+/* ======================================================================== */
+
+int imx_camera_module_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ int ret = 0;
+ struct imx_camera_module *cam_mod = to_imx_camera_module(sd);
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "%d\n", enable);
+
+ if (enable) {
+ if (cam_mod->state == IMX_CAMERA_MODULE_STREAMING)
+ return 0;
+ if (IS_ERR_OR_NULL(cam_mod->active_config)) {
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "no active sensor configuration, cannot start streaming\n");
+ ret = -EFAULT;
+ goto err;
+ }
+ if (cam_mod->state != IMX_CAMERA_MODULE_SW_STANDBY) {
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "sensor is not powered on (in state %d), cannot start streaming\n",
+ cam_mod->state);
+ ret = -EINVAL;
+ goto err;
+ }
+ if (cam_mod->update_config)
+ ret = imx_camera_module_write_config(cam_mod);
+ if (IS_ERR_VALUE(ret))
+ goto err;
+
+ ret = cam_mod->custom.start_streaming(cam_mod);
+ if (IS_ERR_VALUE(ret))
+ goto err;
+ if (!cam_mod->inited && cam_mod->update_config)
+ cam_mod->inited = true;
+ cam_mod->update_config = false;
+ cam_mod->ctrl_updt = 0;
+ mdelay(cam_mod->custom.power_up_delays_ms[2]);
+ cam_mod->state = IMX_CAMERA_MODULE_STREAMING;
+ } else {
+ int pclk;
+ int wait_ms;
+ struct isp_supplemental_sensor_mode_data timings;
+
+ if (cam_mod->state != IMX_CAMERA_MODULE_STREAMING)
+ return 0;
+ ret = cam_mod->custom.stop_streaming(cam_mod);
+ if (IS_ERR_VALUE(ret))
+ goto err;
+
+ ret = imx_camera_module_ioctl(sd,
+ RK_VIDIOC_SENSOR_MODE_DATA,
+ &timings);
+
+ cam_mod->state = IMX_CAMERA_MODULE_SW_STANDBY;
+
+ if (IS_ERR_VALUE(ret))
+ goto err;
+
+ pclk = timings.vt_pix_clk_freq_hz / 1000;
+
+ if (!pclk)
+ goto err;
+
+ wait_ms =
+ (timings.line_length_pck *
+ timings.frame_length_lines) /
+ pclk;
+
+ /*
+ * wait for a frame period to make sure that there is
+ * no pending frame left.
+ */
+
+ msleep(wait_ms + 1);
+ }
+
+ cam_mod->state_before_suspend = cam_mod->state;
+
+ return 0;
+err:
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "failed with error %d\n", ret);
+ return ret;
+}
+
+/* ======================================================================== */
+
+int imx_camera_module_s_power(struct v4l2_subdev *sd, int on)
+{
+ int ret = 0;
+ struct imx_camera_module *cam_mod = to_imx_camera_module(sd);
+ struct v4l2_subdev *af_ctrl;
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "%d state:%d\n", on, cam_mod->state);
+
+ if (on) {
+ if (cam_mod->state == IMX_CAMERA_MODULE_POWER_OFF) {
+ ret = pltfrm_camera_module_s_power(&cam_mod->sd, 1);
+ if (!IS_ERR_VALUE(ret)) {
+ mdelay(cam_mod->custom.power_up_delays_ms[0]);
+ cam_mod->state = IMX_CAMERA_MODULE_HW_STANDBY;
+ }
+ }
+ if (cam_mod->state == IMX_CAMERA_MODULE_HW_STANDBY) {
+ ret = pltfrm_camera_module_set_pin_state(&cam_mod->sd,
+ PLTFRM_CAMERA_MODULE_PIN_PD,
+ PLTFRM_CAMERA_MODULE_PIN_STATE_INACTIVE);
+ if (!IS_ERR_VALUE(ret)) {
+ mdelay(cam_mod->custom.power_up_delays_ms[1]);
+ cam_mod->state = IMX_CAMERA_MODULE_SW_STANDBY;
+ if (!IS_ERR_OR_NULL(
+ cam_mod->custom.init_common) &&
+ cam_mod->custom.init_common(
+ cam_mod))
+ usleep_range(1000, 1500);
+
+ af_ctrl = pltfrm_camera_module_get_af_ctrl(sd);
+ if (!IS_ERR_OR_NULL(af_ctrl)) {
+ v4l2_subdev_call(af_ctrl,
+ core, init, 0);
+ }
+ }
+ }
+ } else {
+ if (cam_mod->state == IMX_CAMERA_MODULE_STREAMING) {
+ ret = imx_camera_module_s_stream(sd, 0);
+ if (!IS_ERR_VALUE(ret))
+ cam_mod->state = IMX_CAMERA_MODULE_SW_STANDBY;
+ }
+ if (cam_mod->state == IMX_CAMERA_MODULE_SW_STANDBY) {
+ ret = pltfrm_camera_module_set_pin_state(
+ &cam_mod->sd,
+ PLTFRM_CAMERA_MODULE_PIN_PD,
+ PLTFRM_CAMERA_MODULE_PIN_STATE_ACTIVE);
+ if (!IS_ERR_VALUE(ret))
+ cam_mod->state = IMX_CAMERA_MODULE_HW_STANDBY;
+ }
+ if (cam_mod->state == IMX_CAMERA_MODULE_HW_STANDBY) {
+ ret = pltfrm_camera_module_s_power(&cam_mod->sd, 0);
+ if (!IS_ERR_VALUE(ret)) {
+ cam_mod->state = IMX_CAMERA_MODULE_POWER_OFF;
+ imx_camera_module_reset(cam_mod);
+ }
+ }
+ }
+
+ cam_mod->state_before_suspend = cam_mod->state;
+
+ if (IS_ERR_VALUE(ret)) {
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "%s failed, camera left in state %d\n",
+ on ? "on" : "off", cam_mod->state);
+ goto err;
+ } else
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "camera powered %s\n", on ? "on" : "off");
+
+ return 0;
+err:
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "failed with error %d\n", ret);
+ return ret;
+}
+
+/* ======================================================================== */
+
+int imx_camera_module_g_ctrl(struct v4l2_subdev *sd,
+ struct v4l2_control *ctrl)
+{
+ struct imx_camera_module *cam_mod = to_imx_camera_module(sd);
+ int ret;
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, " id 0x%x\n", ctrl->id);
+
+ if (ctrl->id == V4L2_CID_FLASH_LED_MODE) {
+ ctrl->value = cam_mod->exp_config.flash_mode;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_FLASH_LED_MODE %d\n",
+ ctrl->value);
+ return 0;
+ }
+
+ if (IS_ERR_OR_NULL(cam_mod->active_config)) {
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "no active configuration\n");
+ return -EFAULT;
+ }
+
+ if (ctrl->id == RK_V4L2_CID_VBLANKING) {
+ ctrl->value = cam_mod->active_config->v_blanking_time_us;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "RK_V4L2_CID_VBLANKING %d\n",
+ ctrl->value);
+ return 0;
+ }
+
+ if ((cam_mod->state != IMX_CAMERA_MODULE_SW_STANDBY) &&
+ (cam_mod->state != IMX_CAMERA_MODULE_STREAMING)) {
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "cannot get controls when camera is off\n");
+ return -EFAULT;
+ }
+
+ if (ctrl->id == V4L2_CID_FOCUS_ABSOLUTE) {
+ struct v4l2_subdev *af_ctrl;
+
+ af_ctrl = pltfrm_camera_module_get_af_ctrl(sd);
+ if (!IS_ERR_OR_NULL(af_ctrl)) {
+ ret = v4l2_subdev_call(af_ctrl, core, g_ctrl, ctrl);
+ return ret;
+ }
+ }
+
+ if (!IS_ERR_OR_NULL(cam_mod->custom.g_ctrl)) {
+ ret = cam_mod->custom.g_ctrl(cam_mod, ctrl->id);
+ if (IS_ERR_VALUE(ret))
+ return ret;
+ }
+
+ switch (ctrl->id) {
+ case V4L2_CID_GAIN:
+ ctrl->value = cam_mod->exp_config.gain;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_GAIN %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_EXPOSURE:
+ ctrl->value = cam_mod->exp_config.exp_time;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_EXPOSURE %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_WHITE_BALANCE_TEMPERATURE:
+ ctrl->value = cam_mod->wb_config.temperature;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_WHITE_BALANCE_TEMPERATURE %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
+ ctrl->value = cam_mod->wb_config.preset_id;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_AUTOGAIN:
+ ctrl->value = cam_mod->exp_config.auto_gain;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_AUTOGAIN %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_EXPOSURE_AUTO:
+ ctrl->value = cam_mod->exp_config.auto_exp;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_EXPOSURE_AUTO %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ ctrl->value = cam_mod->wb_config.auto_wb;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_AUTO_WHITE_BALANCE %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_FOCUS_ABSOLUTE:
+ ctrl->value = cam_mod->af_config.abs_pos;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_FOCUS_ABSOLUTE %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_HFLIP:
+ case V4L2_CID_VFLIP:
+ /* TBD */
+ /* fallthrough */
+ default:
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "failed, unknown ctrl %d\n", ctrl->id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int flash_light_ctrl(
+ struct v4l2_subdev *sd,
+ struct imx_camera_module *cam_mod,
+ int value)
+{
+ return 0;
+}
+
+/* ======================================================================== */
+
+int imx_camera_module_s_ext_ctrls(
+ struct v4l2_subdev *sd,
+ struct v4l2_ext_controls *ctrls)
+{
+ int i;
+ int ctrl_cnt = 0;
+ struct imx_camera_module *cam_mod = to_imx_camera_module(sd);
+ int ret = 0;
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "\n");
+ if (ctrls->count == 0)
+ return -EINVAL;
+
+ for (i = 0; i < ctrls->count; i++) {
+ struct v4l2_ext_control *ctrl;
+ u32 ctrl_updt = 0;
+
+ ctrl = &ctrls->controls[i];
+
+ switch (ctrl->id) {
+ case V4L2_CID_GAIN:
+ ctrl_updt = IMX_CAMERA_MODULE_CTRL_UPDT_GAIN;
+ cam_mod->exp_config.gain = ctrl->value;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_GAIN %d\n",
+ ctrl->value);
+ break;
+ case RK_V4L2_CID_GAIN_PERCENT:
+ ctrl_updt = IMX_CAMERA_MODULE_CTRL_UPDT_GAIN;
+ cam_mod->exp_config.gain_percent = ctrl->value;
+ break;
+ case V4L2_CID_FLASH_LED_MODE:
+ ret = flash_light_ctrl(sd, cam_mod, ctrl->value);
+ if (ret == 0) {
+ cam_mod->exp_config.flash_mode = ctrl->value;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_FLASH_LED_MODE %d\n",
+ ctrl->value);
+ }
+ break;
+ case V4L2_CID_EXPOSURE:
+ ctrl_updt = IMX_CAMERA_MODULE_CTRL_UPDT_EXP_TIME;
+ cam_mod->exp_config.exp_time = ctrl->value;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_EXPOSURE %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_WHITE_BALANCE_TEMPERATURE:
+ ctrl_updt = IMX_CAMERA_MODULE_CTRL_UPDT_WB_TEMPERATURE;
+ cam_mod->wb_config.temperature = ctrl->value;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_WHITE_BALANCE_TEMPERATURE %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
+ ctrl_updt = IMX_CAMERA_MODULE_CTRL_UPDT_PRESET_WB;
+ cam_mod->wb_config.preset_id = ctrl->value;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_AUTOGAIN:
+ ctrl_updt = IMX_CAMERA_MODULE_CTRL_UPDT_AUTO_GAIN;
+ cam_mod->exp_config.auto_gain = ctrl->value;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_AUTOGAIN %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_EXPOSURE_AUTO:
+ ctrl_updt = IMX_CAMERA_MODULE_CTRL_UPDT_AUTO_EXP;
+ cam_mod->exp_config.auto_exp = ctrl->value;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_EXPOSURE_AUTO %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ ctrl_updt = IMX_CAMERA_MODULE_CTRL_UPDT_AUTO_WB;
+ cam_mod->wb_config.auto_wb = ctrl->value;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_AUTO_WHITE_BALANCE %d\n",
+ ctrl->value);
+ break;
+ case RK_V4L2_CID_AUTO_FPS:
+ cam_mod->auto_adjust_fps = ctrl->value;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "RK_V4L2_CID_AUTO_FPS %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_FOCUS_ABSOLUTE:
+ {
+ struct v4l2_subdev *af_ctrl;
+
+ af_ctrl = pltfrm_camera_module_get_af_ctrl(sd);
+ if (!IS_ERR_OR_NULL(af_ctrl)) {
+ struct v4l2_control single_ctrl;
+
+ single_ctrl.id =
+ V4L2_CID_FOCUS_ABSOLUTE;
+ single_ctrl.value = ctrl->value;
+ ret = v4l2_subdev_call(af_ctrl,
+ core, s_ctrl, &single_ctrl);
+ return ret;
+ }
+ }
+ ctrl_updt =
+ IMX_CAMERA_MODULE_CTRL_UPDT_FOCUS_ABSOLUTE;
+ cam_mod->af_config.abs_pos = ctrl->value;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_FOCUS_ABSOLUTE %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_HFLIP:
+ if (ctrl->value)
+ cam_mod->hflip = true;
+ else
+ cam_mod->hflip = false;
+ break;
+ case V4L2_CID_VFLIP:
+ if (ctrl->value)
+ cam_mod->vflip = true;
+ else
+ cam_mod->vflip = false;
+ break;
+ default:
+ pltfrm_camera_module_pr_warn(&cam_mod->sd,
+ "ignoring unknown ctrl 0x%x\n", ctrl->id);
+ break;
+ }
+
+ if (cam_mod->state != IMX_CAMERA_MODULE_SW_STANDBY &&
+ cam_mod->state != IMX_CAMERA_MODULE_STREAMING)
+ cam_mod->ctrl_updt |= ctrl_updt;
+ else if (ctrl_updt)
+ ctrl_cnt++;
+ }
+
+ /* if camera module is already streaming, write through */
+ if (ctrl_cnt &&
+ (cam_mod->state == IMX_CAMERA_MODULE_STREAMING ||
+ cam_mod->state == IMX_CAMERA_MODULE_SW_STANDBY)) {
+ struct imx_camera_module_ext_ctrls imx_ctrls;
+
+ imx_ctrls.ctrls =
+ (struct imx_camera_module_ext_ctrl *)
+ kmalloc(ctrl_cnt * sizeof(struct imx_camera_module_ext_ctrl),
+ GFP_KERNEL);
+
+ if (imx_ctrls.ctrls) {
+ for (i = 0; i < ctrl_cnt; i++) {
+ imx_ctrls.ctrls[i].id = ctrls->controls[i].id;
+ imx_ctrls.ctrls[i].value =
+ ctrls->controls[i].value;
+ }
+
+ imx_ctrls.count = ctrl_cnt;
+
+ ret = cam_mod->custom.s_ext_ctrls(cam_mod, &imx_ctrls);
+
+ kfree(imx_ctrls.ctrls);
+ } else {
+ ret = -ENOMEM;
+ }
+
+ if (IS_ERR_VALUE(ret))
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "failed with error %d\n", ret);
+ }
+
+ return ret;
+}
+
+/* ======================================================================== */
+
+int imx_camera_module_s_ctrl(
+ struct v4l2_subdev *sd,
+ struct v4l2_control *ctrl)
+{
+ struct imx_camera_module *cam_mod = to_imx_camera_module(sd);
+ struct v4l2_ext_control ext_ctrl[1];
+ struct v4l2_ext_controls ext_ctrls;
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "0x%x 0x%x\n", ctrl->id, ctrl->value);
+
+ ext_ctrl[0].id = ctrl->id;
+ ext_ctrl[0].value = ctrl->value;
+
+ ext_ctrls.count = 1;
+ ext_ctrls.controls = ext_ctrl;
+
+ return imx_camera_module_s_ext_ctrls(sd, &ext_ctrls);
+}
+
+/* ======================================================================== */
+
+long imx_camera_module_ioctl(struct v4l2_subdev *sd,
+ unsigned int cmd,
+ void *arg)
+{
+ struct imx_camera_module *cam_mod = to_imx_camera_module(sd);
+ int ret;
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "cmd: 0x%x\n", cmd);
+
+ if (cmd == RK_VIDIOC_SENSOR_MODE_DATA) {
+ struct imx_camera_module_timings imx_timings;
+ struct isp_supplemental_sensor_mode_data *timings =
+ (struct isp_supplemental_sensor_mode_data *)arg;
+
+ if (cam_mod->custom.g_timings)
+ ret = cam_mod->custom.g_timings(cam_mod, &imx_timings);
+ else
+ ret = -EPERM;
+
+ if (IS_ERR_VALUE(ret)) {
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "failed with error %d\n", ret);
+ return ret;
+ }
+
+ timings->sensor_output_width =
+ imx_timings.sensor_output_width;
+ timings->sensor_output_height =
+ imx_timings.sensor_output_height;
+ timings->crop_horizontal_start =
+ imx_timings.crop_horizontal_start;
+ timings->crop_vertical_start =
+ imx_timings.crop_vertical_start;
+ timings->crop_horizontal_end =
+ imx_timings.crop_horizontal_end;
+ timings->crop_vertical_end = imx_timings.crop_vertical_end;
+ timings->line_length_pck = imx_timings.line_length_pck;
+ timings->frame_length_lines = imx_timings.frame_length_lines;
+ timings->vt_pix_clk_freq_hz = imx_timings.vt_pix_clk_freq_hz;
+ timings->binning_factor_x = imx_timings.binning_factor_x;
+ timings->binning_factor_y = imx_timings.binning_factor_y;
+ timings->coarse_integration_time_max_margin =
+ imx_timings.coarse_integration_time_max_margin;
+ timings->coarse_integration_time_min =
+ imx_timings.coarse_integration_time_min;
+ timings->fine_integration_time_max_margin =
+ imx_timings.fine_integration_time_max_margin;
+ timings->fine_integration_time_min =
+ imx_timings.fine_integration_time_min;
+
+ if (cam_mod->custom.g_exposure_valid_frame)
+ timings->exposure_valid_frame =
+ cam_mod->custom.g_exposure_valid_frame(cam_mod);
+ timings->exp_time = cam_mod->exp_config.exp_time;
+ timings->gain = cam_mod->exp_config.gain;
+
+ if (cam_mod->exp_config.exp_time)
+ timings->exp_time = cam_mod->exp_config.exp_time;
+ else
+ timings->exp_time = imx_timings.exp_time;
+
+ if (cam_mod->exp_config.gain)
+ timings->gain = cam_mod->exp_config.gain;
+ else
+ timings->gain = imx_timings.gain;
+ return ret;
+ } else if (cmd == PLTFRM_CIFCAM_G_ITF_CFG) {
+ struct pltfrm_cam_itf *itf_cfg = (struct pltfrm_cam_itf *)arg;
+ struct imx_camera_module_config *config;
+
+ if (cam_mod->custom.num_configs <= 0) {
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "cam_mod->custom.num_configs is NULL, Get interface config failed!\n");
+ return -EINVAL;
+ }
+
+ if (IS_ERR_OR_NULL(cam_mod->active_config))
+ config = &cam_mod->custom.configs[0];
+ else
+ config = cam_mod->active_config;
+
+ *itf_cfg = config->itf_cfg;
+
+ pltfrm_camera_module_ioctl(sd, PLTFRM_CIFCAM_G_ITF_CFG, arg);
+ return 0;
+ } else if (cmd == PLTFRM_CIFCAM_ATTACH) {
+ imx_camera_module_init(cam_mod, &cam_mod->custom);
+ pltfrm_camera_module_ioctl(sd, cmd, arg);
+ return imx_camera_module_attach(cam_mod);
+ }
+
+ ret = pltfrm_camera_module_ioctl(sd, cmd, arg);
+ return ret;
+}
+
+/* ======================================================================== */
+
+int imx_camera_module_get_flip_mirror(
+ struct imx_camera_module *cam_mod)
+{
+ return pltfrm_camera_module_get_flip_mirror(&cam_mod->sd);
+}
+
+/* ======================================================================== */
+
+int imx_camera_module_enum_frameintervals(
+ struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_interval_enum *fie)
+{
+ struct imx_camera_module *cam_mod = to_imx_camera_module(sd);
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "%d\n", fie->index);
+
+ if (fie->index >= cam_mod->custom.num_configs)
+ return -EINVAL;
+ fie->code =
+ cam_mod->custom.configs[fie->index].frm_fmt.code;
+ fie->width =
+ cam_mod->custom.configs[fie->index].frm_fmt.width;
+ fie->height =
+ cam_mod->custom.configs[fie->index].frm_fmt.height;
+ fie->interval.numerator = cam_mod->custom.
+ configs[fie->index].frm_intrvl.interval.numerator;
+ fie->interval.denominator = cam_mod->custom.
+ configs[fie->index].frm_intrvl.interval.denominator;
+ return 0;
+}
+
+/* ======================================================================== */
+
+int imx_camera_module_write_reglist(
+ struct imx_camera_module *cam_mod,
+ const struct imx_camera_module_reg reglist[],
+ int len)
+{
+ return pltfrm_camera_module_write_reglist(&cam_mod->sd, reglist, len);
+}
+
+/* ======================================================================== */
+
+int imx_camera_module_write_reg(
+ struct imx_camera_module *cam_mod,
+ u16 reg,
+ u8 val)
+{
+ return pltfrm_camera_module_write_reg(&cam_mod->sd, reg, val);
+}
+
+/* ======================================================================== */
+
+int imx_camera_module_read_reg(
+ struct imx_camera_module *cam_mod,
+ u16 data_length,
+ u16 reg,
+ u32 *val)
+{
+ return pltfrm_camera_module_read_reg(&cam_mod->sd,
+ data_length, reg, val);
+}
+
+/* ======================================================================== */
+
+int imx_camera_module_read_reg_table(
+ struct imx_camera_module *cam_mod,
+ u16 reg,
+ u32 *val)
+{
+ int i;
+
+ if (cam_mod->state == IMX_CAMERA_MODULE_STREAMING)
+ return pltfrm_camera_module_read_reg(&cam_mod->sd,
+ 1, reg, val);
+
+ if (!IS_ERR_OR_NULL(cam_mod->active_config)) {
+ for (
+ i = cam_mod->active_config->reg_table_num_entries - 1;
+ i > 0;
+ i--) {
+ if (cam_mod->active_config->reg_table[i].reg == reg) {
+ *val = cam_mod->active_config->reg_table[i].val;
+ return 0;
+ }
+ }
+ }
+
+ if (cam_mod->state == IMX_CAMERA_MODULE_SW_STANDBY)
+ return pltfrm_camera_module_read_reg(&cam_mod->sd,
+ 1, reg, val);
+
+ return -EFAULT;
+}
+
+/* ======================================================================== */
+
+int imx_camera_module_init(struct imx_camera_module *cam_mod,
+ struct imx_camera_module_custom_config *custom)
+{
+ int ret = 0;
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "\n");
+
+ imx_camera_module_reset(cam_mod);
+
+ if (IS_ERR_OR_NULL(custom->start_streaming) ||
+ IS_ERR_OR_NULL(custom->stop_streaming) ||
+ IS_ERR_OR_NULL(custom->s_ctrl) ||
+ IS_ERR_OR_NULL(custom->g_ctrl)) {
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "mandatory callback function is missing\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = pltfrm_camera_module_init(&cam_mod->sd, &cam_mod->pltfm_data);
+ if (IS_ERR_VALUE(ret))
+ goto err;
+
+ ret = pltfrm_camera_module_set_pin_state(&cam_mod->sd,
+ PLTFRM_CAMERA_MODULE_PIN_PD,
+ PLTFRM_CAMERA_MODULE_PIN_STATE_INACTIVE);
+ ret = pltfrm_camera_module_set_pin_state(&cam_mod->sd,
+ PLTFRM_CAMERA_MODULE_PIN_RESET,
+ PLTFRM_CAMERA_MODULE_PIN_STATE_ACTIVE);
+ if (IS_ERR_VALUE(ret)) {
+ imx_camera_module_release(cam_mod);
+ goto err;
+ }
+
+ return 0;
+err:
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "failed with error %d\n", ret);
+ return ret;
+}
+
+void imx_camera_module_release(struct imx_camera_module *cam_mod)
+{
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "\n");
+
+ cam_mod->custom.configs = NULL;
+
+ pltfrm_camera_module_release(&cam_mod->sd);
+ v4l2_device_unregister_subdev(&cam_mod->sd);
+}
--- /dev/null
+/*
+ * imx_camera_module.h
+ *
+ * Generic sony sensor driver
+ *
+ * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd.
+ *
+ * Copyright (C) 2012-2014 Intel Mobile Communications GmbH
+ *
+ * Copyright (C) 2008 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+
+#ifndef IMX_CAMERA_MODULE_H
+#define IMX_CAMERA_MODULE_H
+#include <linux/workqueue.h>
+#include <linux/platform_data/rk_isp10_platform_camera_module.h>
+#include <linux/platform_data/rk_isp10_platform.h>
+/*
+ * TODO: references to v4l2 should be reomved from here and go into a
+ * platform dependent wrapper
+ */
+
+#define IMX_CAMERA_MODULE_REG_TYPE_DATA PLTFRM_CAMERA_MODULE_REG_TYPE_DATA
+#define IMX_CAMERA_MODULE_REG_TYPE_TIMEOUT PLTFRM_CAMERA_MODULE_REG_TYPE_TIMEOUT
+#define imx_camera_module_csi_config
+#define imx_camera_module_reg pltfrm_camera_module_reg
+
+#define IMX_FLIP_BIT_MASK 0x2
+#define IMX_MIRROR_BIT_MASK 0x1
+
+#define IMX_CAMERA_MODULE_CTRL_UPDT_GAIN 0x01
+#define IMX_CAMERA_MODULE_CTRL_UPDT_EXP_TIME 0x02
+#define IMX_CAMERA_MODULE_CTRL_UPDT_WB_TEMPERATURE 0x04
+#define IMX_CAMERA_MODULE_CTRL_UPDT_AUTO_WB 0x08
+#define IMX_CAMERA_MODULE_CTRL_UPDT_AUTO_GAIN 0x10
+#define IMX_CAMERA_MODULE_CTRL_UPDT_AUTO_EXP 0x20
+#define IMX_CAMERA_MODULE_CTRL_UPDT_FOCUS_ABSOLUTE 0x40
+#define IMX_CAMERA_MODULE_CTRL_UPDT_PRESET_WB 0x80
+
+enum imx_camera_module_state {
+ IMX_CAMERA_MODULE_POWER_OFF = 0,
+ IMX_CAMERA_MODULE_HW_STANDBY = 1,
+ IMX_CAMERA_MODULE_SW_STANDBY = 2,
+ IMX_CAMERA_MODULE_STREAMING = 3
+};
+
+struct imx_camera_module;
+
+struct imx_camera_module_timings {
+ u32 coarse_integration_time_min;
+ u32 coarse_integration_time_max_margin;
+ u32 fine_integration_time_min;
+ u32 fine_integration_time_max_margin;
+ u32 frame_length_lines;
+ u32 line_length_pck;
+ u32 vt_pix_clk_freq_hz;
+ u32 sensor_output_width;
+ u32 sensor_output_height;
+ u32 crop_horizontal_start;
+ u32 crop_vertical_start;
+ u32 crop_horizontal_end;
+ u32 crop_vertical_end;
+ u8 binning_factor_x;
+ u8 binning_factor_y;
+ u32 exp_time;
+ u32 gain;
+};
+
+struct imx_camera_module_config {
+ const char *name;
+ struct v4l2_mbus_framefmt frm_fmt;
+ struct v4l2_subdev_frame_interval frm_intrvl;
+ bool auto_exp_enabled;
+ bool auto_gain_enabled;
+ bool auto_wb_enabled;
+ struct imx_camera_module_reg *reg_table;
+ u32 reg_table_num_entries;
+ u32 reg_diff_table_num_entries;
+ u32 v_blanking_time_us;
+ u32 line_length_pck;
+ u32 frame_length_lines;
+ struct imx_camera_module_timings timings;
+ bool soft_reset;
+ bool ignore_measurement_check;
+ struct pltfrm_cam_itf itf_cfg;
+};
+
+struct imx_camera_module_exp_config {
+ u32 exp_time;
+ bool auto_exp;
+ u16 gain;
+ u16 gain_percent;
+ bool auto_gain;
+ enum v4l2_flash_led_mode flash_mode;
+};
+
+struct imx_camera_module_wb_config {
+ u32 temperature;
+ u32 preset_id;
+ bool auto_wb;
+};
+
+struct imx_camera_module_af_config {
+ u32 abs_pos;
+ u32 rel_pos;
+};
+
+struct imx_camera_module_ext_ctrl {
+ /* public */
+ u32 id;
+ u32 value;
+ __u32 reserved2[1];
+};
+
+struct imx_camera_module_ext_ctrls {
+ /* public */
+ u32 count;
+ struct imx_camera_module_ext_ctrl *ctrls;
+};
+
+/*
+ * start_streaming: (mandatory) will be called when sensor should be
+ * put into streaming mode right after the base config has been
+ * written to the sensor. After a successful call of this function
+ * the sensor should start delivering frame data.
+ *
+ * stop_streaming: (mandatory) will be called when sensor should stop
+ * delivering data. After a successful call of this function the
+ * sensor should not deliver any more frame data.
+ *
+ * check_camera_id: (optional) will be called when the sensor is
+ * powered on. If provided should check the sensor ID/version
+ * required by the custom driver. Register access should be
+ * possible when this function is invoked.
+ *
+ * s_ctrl: (mandatory) will be called at the successful end of
+ * imx_camera_module_s_ctrl with the ctrl_id as argument.
+ *
+ * priv: (optional) for private data used by the custom driver.
+ */
+struct imx_camera_module_custom_config {
+ int (*start_streaming)(struct imx_camera_module *cam_mod);
+ int (*stop_streaming)(struct imx_camera_module *cam_mod);
+ int (*check_camera_id)(struct imx_camera_module *cam_mod);
+ int (*s_ctrl)(struct imx_camera_module *cam_mod, u32 ctrl_id);
+ int (*g_ctrl)(struct imx_camera_module *cam_mod, u32 ctrl_id);
+ int (*g_timings)(struct imx_camera_module *cam_mod,
+ struct imx_camera_module_timings *timings);
+ int (*g_exposure_valid_frame)(struct imx_camera_module *cam_mod);
+ int (*s_ext_ctrls)(struct imx_camera_module *cam_mod,
+ struct imx_camera_module_ext_ctrls *ctrls);
+ int (*set_flip)(struct imx_camera_module *cam_mod);
+ int (*init_common)(struct imx_camera_module *cam_mod);
+ struct imx_camera_module_config *configs;
+ u32 num_configs;
+ u32 power_up_delays_ms[3];
+ void *priv;
+};
+
+struct imx_camera_module_otp_work {
+ struct work_struct work;
+ struct workqueue_struct *wq;
+ void *cam_mod;
+};
+
+struct imx_camera_module {
+ /* public */
+ struct v4l2_subdev sd;
+ struct v4l2_mbus_framefmt frm_fmt;
+ struct v4l2_subdev_frame_interval frm_intrvl;
+ struct imx_camera_module_exp_config exp_config;
+ struct imx_camera_module_wb_config wb_config;
+ struct imx_camera_module_af_config af_config;
+ struct imx_camera_module_custom_config custom;
+ enum imx_camera_module_state state;
+ enum imx_camera_module_state state_before_suspend;
+ struct imx_camera_module_config *active_config;
+ struct imx_camera_module_otp_work otp_work;
+ u32 ctrl_updt;
+ u32 vts_cur;
+ u32 vts_min;
+ bool auto_adjust_fps;
+ bool update_config;
+ bool frm_fmt_valid;
+ bool frm_intrvl_valid;
+ bool hflip;
+ bool vflip;
+ u32 rotation;
+ void *pltfm_data;
+ bool inited;
+};
+
+#define imx_camera_module_pr_info(cam_mod, fmt, arg...) \
+ pltfrm_camera_module_pr_info(&cam_mod->sd, fmt, ## arg)
+#define imx_camera_module_pr_debug(cam_mod, fmt, arg...) \
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, fmt, ## arg)
+#define imx_camera_module_pr_warn(cam_mod, fmt, arg...) \
+ pltfrm_camera_module_pr_warn(&cam_mod->sd, fmt, ## arg)
+#define imx_camera_module_pr_err(cam_mod, fmt, arg...) \
+ pltfrm_camera_module_pr_err(&cam_mod->sd, fmt, ## arg)
+
+int imx_camera_module_write_reglist(
+ struct imx_camera_module *cam_mod,
+ const struct imx_camera_module_reg reglist[],
+ int len);
+
+int imx_camera_module_write_reg(
+ struct imx_camera_module *cam_mod,
+ u16 reg,
+ u8 val);
+
+int imx_camera_module_read_reg(
+ struct imx_camera_module *cam_mod,
+ u16 data_length,
+ u16 reg,
+ u32 *val);
+
+int imx_camera_module_read_reg_table(
+ struct imx_camera_module *cam_mod,
+ u16 reg,
+ u32 *val);
+
+int imx_camera_module_s_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format);
+
+int imx_camera_module_g_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format);
+
+int imx_camera_module_s_frame_interval(
+ struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *interval);
+
+int imx_camera_module_s_stream(
+ struct v4l2_subdev *sd,
+ int enable);
+
+int imx_camera_module_s_power(
+ struct v4l2_subdev *sd,
+ int on);
+
+int imx_camera_module_g_ctrl(
+ struct v4l2_subdev *sd,
+ struct v4l2_control *ctrl);
+
+int imx_camera_module_s_ctrl(
+ struct v4l2_subdev *sd,
+ struct v4l2_control *ctrl);
+
+int imx_camera_module_s_ext_ctrls(
+ struct v4l2_subdev *sd,
+ struct v4l2_ext_controls *ctrls);
+
+int imx_camera_module_enum_frameintervals(
+ struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_interval_enum *fie);
+
+int imx_camera_module_init(
+ struct imx_camera_module *cam_mod,
+ struct imx_camera_module_custom_config *custom);
+
+void imx_camera_module_release(
+ struct imx_camera_module *cam_mod);
+
+long imx_camera_module_ioctl(struct v4l2_subdev *sd,
+ unsigned int cmd,
+ void *arg);
+
+int imx_camera_module_get_flip_mirror(
+ struct imx_camera_module *cam_mod);
+#endif
--- /dev/null
+/*
+ * drivers/media/i2c/soc_camera/xgold/ov2710.c
+ *
+ * ov2710 sensor driver
+ *
+ * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd.
+ *
+ * Copyright (C) 2012-2014 Intel Mobile Communications GmbH
+ *
+ * Copyright (C) 2008 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ * Note:
+ *
+ * v0.1.0:
+ * 1. Initialize version;
+ * 2. Stream on sensor in configuration,
+ * and stream off sensor after 1frame;
+ * 3. Stream delay time is define in power_up_delays_ms[2];
+ */
+
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <media/v4l2-subdev.h>
+#include <media/videobuf-core.h>
+#include <linux/slab.h>
+#include <media/v4l2-controls_rockchip.h>
+#include "ov_camera_module.h"
+
+#define OV2710_DRIVER_NAME "ov2710"
+
+#define OV2710_FETCH_LSB_GAIN(VAL) (VAL & 0x00FF) /* gain[7:0] */
+#define OV2710_FETCH_MSB_GAIN(VAL) ((VAL >> 8) & 0x1) /* gain[10:8] */
+#define OV2710_AEC_PK_LONG_GAIN_HIGH_REG 0x350a /* Bit 8 */
+#define OV2710_AEC_PK_LONG_GAIN_LOW_REG 0x350b /* Bits 0 -7 */
+
+#define OV2710_AEC_PK_LONG_EXPO_3RD_REG 0x3500 /* Exposure Bits 16-19 */
+#define OV2710_AEC_PK_LONG_EXPO_2ND_REG 0x3501 /* Exposure Bits 8-15 */
+#define OV2710_AEC_PK_LONG_EXPO_1ST_REG 0x3502 /* Exposure Bits 0-7 */
+
+#define OV2710_AEC_GROUP_UPDATE_ADDRESS 0x3212
+#define OV2710_AEC_GROUP_UPDATE_START_DATA 0x00
+#define OV2710_AEC_GROUP_UPDATE_END_DATA 0x10
+#define OV2710_AEC_GROUP_UPDATE_END_LAUNCH 0xA0
+
+#define OV2710_FETCH_3RD_BYTE_EXP(VAL) (((VAL) >> 12) & 0xF) /* 4 Bits */
+#define OV2710_FETCH_2ND_BYTE_EXP(VAL) (((VAL) >> 4) & 0xFF) /* 8 Bits */
+#define OV2710_FETCH_1ST_BYTE_EXP(VAL) (((VAL) & 0x0F) << 4) /* 4 Bits */
+
+#define OV2710_PIDH_ADDR 0x300A
+#define OV2710_PIDL_ADDR 0x300B
+
+/* High byte of product ID */
+#define OV2710_PIDH_MAGIC 0x27
+/* Low byte of product ID */
+#define OV2710_PIDL_MAGIC 0x10
+
+#define OV2710_EXT_CLK 24000000
+#define OV2710_PLL_PREDIV0_REG 0x3088
+#define OV2710_PLL_PREDIV_REG 0x3080
+#define OV2710_PLL_MUL_HIGH_REG 0x3081
+#define OV2710_PLL_MUL_LOW_REG 0x3082
+#define OV2710_PLL_SPDIV_REG 0x3086
+#define OV2710_PLL_DIVSYS_REG 0x3084
+#define OV2710_TIMING_VTS_HIGH_REG 0x380e
+#define OV2710_TIMING_VTS_LOW_REG 0x380f
+#define OV2710_TIMING_HTS_HIGH_REG 0x380c
+#define OV2710_TIMING_HTS_LOW_REG 0x380d
+#define OV2710_FINE_INTG_TIME_MIN 0
+#define OV2710_FINE_INTG_TIME_MAX_MARGIN 0
+#define OV2710_COARSE_INTG_TIME_MIN 1
+#define OV2710_COARSE_INTG_TIME_MAX_MARGIN 4
+#define OV2710_TIMING_X_INC 0x3814
+#define OV2710_TIMING_Y_INC 0x3815
+#define OV2710_HORIZONTAL_START_HIGH_REG 0x3800
+#define OV2710_HORIZONTAL_START_LOW_REG 0x3801
+#define OV2710_VERTICAL_START_HIGH_REG 0x3802
+#define OV2710_VERTICAL_START_LOW_REG 0x3803
+#define OV2710_HORIZONTAL_END_HIGH_REG 0x3804
+#define OV2710_HORIZONTAL_END_LOW_REG 0x3805
+#define OV2710_VERTICAL_END_HIGH_REG 0x3806
+#define OV2710_VERTICAL_END_LOW_REG 0x3807
+#define OV2710_HORIZONTAL_OUTPUT_SIZE_HIGH_REG 0x3808
+#define OV2710_HORIZONTAL_OUTPUT_SIZE_LOW_REG 0x3809
+#define OV2710_VERTICAL_OUTPUT_SIZE_HIGH_REG 0x380a
+#define OV2710_VERTICAL_OUTPUT_SIZE_LOW_REG 0x380b
+#define OV2710_H_WIN_OFF_HIGH_REG 0x3810
+#define OV2710_H_WIN_OFF_LOW_REG 0x3811
+#define OV2710_V_WIN_OFF_HIGH_REG 0x3812
+#define OV2710_V_WIN_OFF_LOW_REG 0x3813
+
+#define OV2710_ANA_ARRAR01 0x3621
+#define OV2710_TIMING_CONCTROL_VH 0x3803
+#define OV2710_TIMING_CONCTROL18 0x3818
+
+/* ======================================================================== */
+/* Base sensor configs */
+/* ======================================================================== */
+/* MCLK:24MHz 1920x1080 30fps mipi 1lane 800Mbps/lane */
+static struct ov_camera_module_reg ov2710_init_tab_1920_1080_30fps[] = {
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3008, 0x82},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3008, 0x42},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4201, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4202, 0x0f},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3103, 0x93},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3017, 0x7f},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3018, 0xfc},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3706, 0x61},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3712, 0x0c},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3630, 0x6d},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3800, 0x01},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3801, 0xb4},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3802, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3803, 0x0a},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3818, 0x80},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3804, 0x07},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3805, 0x80},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3806, 0x04},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3807, 0x38},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3808, 0x07},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3809, 0x80},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380a, 0x04},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380b, 0x38},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3810, 0x10},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3811, 0x06},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3812, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3813, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3621, 0x04},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3604, 0x60},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3603, 0xa7},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3631, 0x26},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3600, 0x04},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3620, 0x37},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3623, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3702, 0x9e},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3703, 0x5c},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3704, 0x40},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x370d, 0x0f},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3713, 0x9f},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3714, 0x4c},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3710, 0x9e},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3801, 0xc4},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3605, 0x05},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3606, 0x3f},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x302d, 0x90},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x370b, 0x40},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3716, 0x31},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3707, 0x52},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380d, 0x74},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5181, 0x20},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x518f, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4301, 0xff},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4303, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3a00, 0x78},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x300f, 0x88},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3011, 0x28},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3a1a, 0x06},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3a18, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3a19, 0x7a},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3a13, 0x54},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x382e, 0x0f},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x381a, 0x1a},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x401d, 0x02},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5688, 0x03},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5684, 0x07},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5685, 0xa0},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5686, 0x04},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5687, 0x43},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3011, 0x0a},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x300f, 0x8a},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3017, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3018, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x300e, 0x04},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4801, 0x0f},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x300f, 0xc3},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3a0f, 0x40},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3a10, 0x38},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3a1b, 0x48},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3a1e, 0x30},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3a11, 0x90},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3a1f, 0x10},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380c, 0x09},/* HTS H */
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380d, 0x74},/* HTS L */
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380e, 0x04},/* VTS H */
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380f, 0x50},/* VTS L */
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3500, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3501, 0x28},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3502, 0x90},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3503, 0x07},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x350a, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x350b, 0x1f},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5000, 0x5f},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5001, 0x4e},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3406, 0x01},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3400, 0x04},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3401, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3402, 0x04},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3403, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3404, 0x04},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3405, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4800, 0x24},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4201, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4202, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3008, 0x02},
+{OV_CAMERA_MODULE_REG_TYPE_TIMEOUT, 0x0000, 40},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3008, 0x42},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4201, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4202, 0x0f}
+};
+
+/* ======================================================================== */
+static struct ov_camera_module_config ov2710_configs[] = {
+ {
+ .name = "1920x1080_30fps",
+ .frm_fmt = {
+ .width = 1920,
+ .height = 1080,
+ .code = MEDIA_BUS_FMT_SBGGR10_1X10
+ },
+ .frm_intrvl = {
+ .interval = {
+ .numerator = 1,
+ .denominator = 30
+ }
+ },
+ .auto_exp_enabled = false,
+ .auto_gain_enabled = false,
+ .auto_wb_enabled = false,
+ .reg_table = (void *)ov2710_init_tab_1920_1080_30fps,
+ .reg_table_num_entries =
+ sizeof(ov2710_init_tab_1920_1080_30fps) /
+ sizeof(ov2710_init_tab_1920_1080_30fps[0]),
+ .v_blanking_time_us = 3078,
+ .ignore_measurement_check = 1,
+ PLTFRM_CAM_ITF_MIPI_CFG(0, 1, 800, 24000000)
+ }
+};
+
+/*--------------------------------------------------------------------------*/
+static int ov2710_set_flip(
+ struct ov_camera_module *cam_mod,
+ struct pltfrm_camera_module_reg reglist[],
+ int len)
+{
+ int i, mode = 0;
+ u16 match_reg[3];
+
+ mode = ov_camera_module_get_flip_mirror(cam_mod);
+
+ if (mode == -1) {
+ ov_camera_module_pr_debug(
+ cam_mod,
+ "dts don't set flip, return!\n");
+ return 0;
+ }
+
+ if (mode == OV_FLIP_BIT_MASK) {
+ match_reg[0] = 0x04;
+ match_reg[1] = 0x09;
+ match_reg[2] = 0xa0;
+ } else if (mode == OV_MIRROR_BIT_MASK) {
+ match_reg[0] = 0x14;
+ match_reg[1] = 0x0a;
+ match_reg[2] = 0xc0;
+ } else if (mode == (OV_MIRROR_BIT_MASK |
+ OV_FLIP_BIT_MASK)) {
+ match_reg[0] = 0x14;
+ match_reg[1] = 0x09;
+ match_reg[2] = 0xe0;
+ } else {
+ match_reg[0] = 0x04;
+ match_reg[1] = 0x0a;
+ match_reg[2] = 0x80;
+ }
+
+ for (i = len; i > 0; i--) {
+ if (reglist[i].reg == OV2710_ANA_ARRAR01)
+ reglist[i].val = match_reg[0];
+ else if (reglist[i].reg == OV2710_TIMING_CONCTROL_VH)
+ reglist[i].val = match_reg[1];
+ else if (reglist[i].reg == OV2710_TIMING_CONCTROL18)
+ reglist[i].val = match_reg[2];
+ }
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+static int OV2710_g_VTS(struct ov_camera_module *cam_mod, u32 *vts)
+{
+ u32 msb, lsb;
+ int ret;
+
+ ret = ov_camera_module_read_reg_table(
+ cam_mod,
+ OV2710_TIMING_VTS_HIGH_REG,
+ &msb);
+ if (IS_ERR_VALUE(ret))
+ goto err;
+
+ ret = ov_camera_module_read_reg_table(
+ cam_mod,
+ OV2710_TIMING_VTS_LOW_REG,
+ &lsb);
+ if (IS_ERR_VALUE(ret))
+ goto err;
+
+ *vts = (msb << 8) | lsb;
+
+ return 0;
+err:
+ ov_camera_module_pr_err(cam_mod,
+ "failed with error (%d)\n", ret);
+ return ret;
+}
+
+static int OV2710_auto_adjust_fps(struct ov_camera_module *cam_mod,
+ u32 exp_time)
+{
+ int ret;
+ u32 vts;
+
+ if ((cam_mod->exp_config.exp_time + OV2710_COARSE_INTG_TIME_MAX_MARGIN)
+ > cam_mod->vts_min)
+ vts = cam_mod->exp_config.exp_time +
+ OV2710_COARSE_INTG_TIME_MAX_MARGIN;
+ else
+ vts = cam_mod->vts_min;
+
+ /*
+ * if (cam_mod->fps_ctrl > 0 && cam_mod->fps_ctrl < 100)
+ * vts = vts * 100 / cam_mod->fps_ctrl;
+ */
+
+ if (vts > 0xfff)
+ vts = 0xfff;
+ else
+ vts = vts;/* VTS value is 0x380e[3:0]/380f[7:0] */
+
+ ret = ov_camera_module_write_reg(cam_mod,
+ OV2710_TIMING_VTS_LOW_REG,
+ vts & 0xFF);
+ ret |= ov_camera_module_write_reg(cam_mod,
+ OV2710_TIMING_VTS_HIGH_REG,
+ (vts >> 8) & 0x0F);
+
+ if (IS_ERR_VALUE(ret))
+ ov_camera_module_pr_err(cam_mod,
+ "failed with error (%d)\n", ret);
+ else
+ ov_camera_module_pr_debug(cam_mod,
+ "updated vts = 0x%x,vts_min=0x%x\n",
+ vts, cam_mod->vts_min);
+
+ return ret;
+}
+
+static int ov2710_write_aec(struct ov_camera_module *cam_mod)
+{
+ int ret = 0;
+
+ ov_camera_module_pr_debug(cam_mod,
+ "exp_time = %d lines, gain = %d, flash_mode = %d\n",
+ cam_mod->exp_config.exp_time,
+ cam_mod->exp_config.gain,
+ cam_mod->exp_config.flash_mode);
+
+ /*
+ * if the sensor is already streaming, write to shadow registers,
+ * if the sensor is in SW standby, write to active registers,
+ * if the sensor is off/registers are not writeable, do nothing
+ */
+ if ((cam_mod->state == OV_CAMERA_MODULE_SW_STANDBY) ||
+ (cam_mod->state == OV_CAMERA_MODULE_STREAMING)) {
+ u32 a_gain = cam_mod->exp_config.gain;
+ u32 exp_time = cam_mod->exp_config.exp_time;
+
+ a_gain = a_gain * cam_mod->exp_config.gain_percent / 100;
+
+ if (cam_mod->state == OV_CAMERA_MODULE_STREAMING)
+ ret = ov_camera_module_write_reg(cam_mod,
+ OV2710_AEC_GROUP_UPDATE_ADDRESS,
+ OV2710_AEC_GROUP_UPDATE_START_DATA);
+ if (!IS_ERR_VALUE(ret) && cam_mod->auto_adjust_fps)
+ ret = OV2710_auto_adjust_fps(cam_mod,
+ cam_mod->exp_config.exp_time);
+ ret |= ov_camera_module_write_reg(cam_mod,
+ OV2710_AEC_PK_LONG_GAIN_HIGH_REG,
+ OV2710_FETCH_MSB_GAIN(a_gain));
+ ret |= ov_camera_module_write_reg(cam_mod,
+ OV2710_AEC_PK_LONG_GAIN_LOW_REG,
+ OV2710_FETCH_LSB_GAIN(a_gain));
+ ret = ov_camera_module_write_reg(cam_mod,
+ OV2710_AEC_PK_LONG_EXPO_3RD_REG,
+ OV2710_FETCH_3RD_BYTE_EXP(exp_time));
+ ret |= ov_camera_module_write_reg(cam_mod,
+ OV2710_AEC_PK_LONG_EXPO_2ND_REG,
+ OV2710_FETCH_2ND_BYTE_EXP(exp_time));
+ ret |= ov_camera_module_write_reg(cam_mod,
+ OV2710_AEC_PK_LONG_EXPO_1ST_REG,
+ OV2710_FETCH_1ST_BYTE_EXP(exp_time));
+ if (cam_mod->state == OV_CAMERA_MODULE_STREAMING) {
+ ret = ov_camera_module_write_reg(cam_mod,
+ OV2710_AEC_GROUP_UPDATE_ADDRESS,
+ OV2710_AEC_GROUP_UPDATE_END_DATA);
+ ret = ov_camera_module_write_reg(cam_mod,
+ OV2710_AEC_GROUP_UPDATE_ADDRESS,
+ OV2710_AEC_GROUP_UPDATE_END_LAUNCH);
+ }
+ }
+
+ if (IS_ERR_VALUE(ret))
+ ov_camera_module_pr_err(cam_mod,
+ "failed with error (%d)\n", ret);
+ return ret;
+}
+
+static int ov2710_g_ctrl(struct ov_camera_module *cam_mod, u32 ctrl_id)
+{
+ int ret = 0;
+
+ ov_camera_module_pr_debug(cam_mod, "\n");
+
+ switch (ctrl_id) {
+ case V4L2_CID_GAIN:
+ case V4L2_CID_EXPOSURE:
+ case V4L2_CID_FLASH_LED_MODE:
+ /* nothing to be done here */
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ if (IS_ERR_VALUE(ret))
+ ov_camera_module_pr_debug(cam_mod,
+ "failed with error (%d)\n", ret);
+ return ret;
+}
+
+/*--------------------------------------------------------------------------*/
+
+static int ov2710_filltimings(struct ov_camera_module_custom_config *custom)
+{
+ int i, j;
+ u32 win_h_off = 0, win_v_off = 0;
+ struct ov_camera_module_config *config;
+ struct ov_camera_module_timings *timings;
+ struct ov_camera_module_reg *reg_table;
+ int reg_table_num_entries;
+
+ for (i = 0; i < custom->num_configs; i++) {
+ config = &custom->configs[i];
+ reg_table = config->reg_table;
+ reg_table_num_entries = config->reg_table_num_entries;
+ timings = &config->timings;
+
+ memset(timings, 0x00, sizeof(*timings));
+ for (j = 0; j < reg_table_num_entries; j++) {
+ switch (reg_table[j].reg) {
+ case OV2710_TIMING_VTS_HIGH_REG:
+ timings->frame_length_lines =
+ ((reg_table[j].val << 8) |
+ (timings->frame_length_lines & 0xff));
+ break;
+ case OV2710_TIMING_VTS_LOW_REG:
+ timings->frame_length_lines =
+ (reg_table[j].val |
+ (timings->frame_length_lines & 0xff00));
+ break;
+ case OV2710_TIMING_HTS_HIGH_REG:
+ timings->line_length_pck =
+ ((reg_table[j].val << 8) |
+ timings->line_length_pck);
+ break;
+ case OV2710_TIMING_HTS_LOW_REG:
+ timings->line_length_pck =
+ (reg_table[j].val |
+ (timings->line_length_pck & 0xff00));
+ break;
+ case OV2710_TIMING_X_INC:
+ timings->binning_factor_x =
+ ((reg_table[j].val >> 4) + 1) / 2;
+ if (timings->binning_factor_x == 0)
+ timings->binning_factor_x = 1;
+ break;
+ case OV2710_TIMING_Y_INC:
+ timings->binning_factor_y =
+ ((reg_table[j].val >> 4) + 1) / 2;
+ if (timings->binning_factor_y == 0)
+ timings->binning_factor_y = 1;
+ break;
+ case OV2710_HORIZONTAL_START_HIGH_REG:
+ timings->crop_horizontal_start =
+ ((reg_table[j].val << 8) |
+ (timings->crop_horizontal_start &
+ 0xff));
+ break;
+ case OV2710_HORIZONTAL_START_LOW_REG:
+ timings->crop_horizontal_start =
+ (reg_table[j].val |
+ (timings->crop_horizontal_start &
+ 0xff00));
+ break;
+ case OV2710_VERTICAL_START_HIGH_REG:
+ timings->crop_vertical_start =
+ ((reg_table[j].val << 8) |
+ (timings->crop_vertical_start & 0xff));
+ break;
+ case OV2710_VERTICAL_START_LOW_REG:
+ timings->crop_vertical_start =
+ ((reg_table[j].val) |
+ (timings->crop_vertical_start &
+ 0xff00));
+ break;
+ case OV2710_HORIZONTAL_END_HIGH_REG:
+ timings->crop_horizontal_end =
+ ((reg_table[j].val << 8) |
+ (timings->crop_horizontal_end & 0xff));
+ break;
+ case OV2710_HORIZONTAL_END_LOW_REG:
+ timings->crop_horizontal_end =
+ (reg_table[j].val |
+ (timings->crop_horizontal_end &
+ 0xff00));
+ break;
+ case OV2710_VERTICAL_END_HIGH_REG:
+ timings->crop_vertical_end =
+ ((reg_table[j].val << 8) |
+ (timings->crop_vertical_end & 0xff));
+ break;
+ case OV2710_VERTICAL_END_LOW_REG:
+ timings->crop_vertical_end =
+ (reg_table[j].val |
+ (timings->crop_vertical_end & 0xff00));
+ break;
+ case OV2710_H_WIN_OFF_HIGH_REG:
+ win_h_off = (reg_table[j].val & 0xf) << 8;
+ break;
+ case OV2710_H_WIN_OFF_LOW_REG:
+ win_h_off |= (reg_table[j].val & 0xff);
+ break;
+ case OV2710_V_WIN_OFF_HIGH_REG:
+ win_v_off = (reg_table[j].val & 0xf) << 8;
+ break;
+ case OV2710_V_WIN_OFF_LOW_REG:
+ win_v_off |= (reg_table[j].val & 0xff);
+ break;
+ case OV2710_HORIZONTAL_OUTPUT_SIZE_HIGH_REG:
+ timings->sensor_output_width =
+ ((reg_table[j].val << 8) |
+ (timings->sensor_output_width & 0xff));
+ break;
+ case OV2710_HORIZONTAL_OUTPUT_SIZE_LOW_REG:
+ timings->sensor_output_width =
+ (reg_table[j].val |
+ (timings->sensor_output_width &
+ 0xff00));
+ break;
+ case OV2710_VERTICAL_OUTPUT_SIZE_HIGH_REG:
+ timings->sensor_output_height =
+ ((reg_table[j].val << 8) |
+ (timings->sensor_output_height & 0xff));
+ break;
+ case OV2710_VERTICAL_OUTPUT_SIZE_LOW_REG:
+ timings->sensor_output_height =
+ (reg_table[j].val |
+ (timings->sensor_output_height &
+ 0xff00));
+ break;
+ }
+ }
+
+ timings->crop_horizontal_start += win_h_off;
+ timings->crop_horizontal_end -= win_h_off;
+ timings->crop_vertical_start += win_v_off;
+ timings->crop_vertical_end -= win_v_off;
+
+ timings->exp_time >>= 4;
+ timings->vt_pix_clk_freq_hz =
+ config->frm_intrvl.interval.denominator *
+ timings->frame_length_lines *
+ timings->line_length_pck;
+
+ timings->coarse_integration_time_min =
+ OV2710_COARSE_INTG_TIME_MIN;
+ timings->coarse_integration_time_max_margin =
+ OV2710_COARSE_INTG_TIME_MAX_MARGIN;
+
+ /* OV Sensor do not use fine integration time. */
+ timings->fine_integration_time_min =
+ OV2710_FINE_INTG_TIME_MIN;
+ timings->fine_integration_time_max_margin =
+ OV2710_FINE_INTG_TIME_MAX_MARGIN;
+ }
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+static int ov2710_g_timings(struct ov_camera_module *cam_mod,
+ struct ov_camera_module_timings *timings)
+{
+ int ret = 0;
+ unsigned int vts;
+
+ if (IS_ERR_OR_NULL(cam_mod->active_config))
+ goto err;
+
+ *timings = cam_mod->active_config->timings;
+
+ vts = (!cam_mod->vts_cur) ?
+ timings->frame_length_lines :
+ cam_mod->vts_cur;
+ if (cam_mod->frm_intrvl_valid)
+ timings->vt_pix_clk_freq_hz =
+ cam_mod->frm_intrvl.interval.denominator
+ * vts
+ * timings->line_length_pck;
+ else
+ timings->vt_pix_clk_freq_hz =
+ cam_mod->active_config->frm_intrvl.interval.denominator *
+ vts * timings->line_length_pck;
+
+ return ret;
+err:
+ ov_camera_module_pr_err(cam_mod,
+ "failed with error (%d)\n", ret);
+ return ret;
+}
+
+/*--------------------------------------------------------------------------*/
+
+static int ov2710_s_ctrl(struct ov_camera_module *cam_mod, u32 ctrl_id)
+{
+ int ret = 0;
+
+ ov_camera_module_pr_debug(cam_mod, "\n");
+
+ switch (ctrl_id) {
+ case V4L2_CID_GAIN:
+ case V4L2_CID_EXPOSURE:
+ ret = ov2710_write_aec(cam_mod);
+ break;
+ case V4L2_CID_FLASH_LED_MODE:
+ /* nothing to be done here */
+ break;
+ case V4L2_CID_FOCUS_ABSOLUTE:
+ /* todo*/
+ break;
+ /*
+ * case RK_V4L2_CID_FPS_CTRL:
+ * if (cam_mod->auto_adjust_fps)
+ * ret = OV2710_auto_adjust_fps(
+ * cam_mod,
+ * cam_mod->exp_config.exp_time);
+ * break;
+ */
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ if (IS_ERR_VALUE(ret))
+ ov_camera_module_pr_err(cam_mod,
+ "failed with error (%d)\n", ret);
+ return ret;
+}
+
+/*--------------------------------------------------------------------------*/
+
+static int ov2710_s_ext_ctrls(struct ov_camera_module *cam_mod,
+ struct ov_camera_module_ext_ctrls *ctrls)
+{
+ int ret = 0;
+
+ /* Handles only exposure and gain together special case. */
+ if (ctrls->count == 1)
+ ret = ov2710_s_ctrl(cam_mod, ctrls->ctrls[0].id);
+ else if ((ctrls->count == 3) &&
+ (ctrls->ctrls[0].id == V4L2_CID_GAIN ||
+ ctrls->ctrls[0].id == V4L2_CID_EXPOSURE ||
+ ctrls->ctrls[1].id == V4L2_CID_GAIN ||
+ ctrls->ctrls[1].id == V4L2_CID_EXPOSURE))
+ ret = ov2710_write_aec(cam_mod);
+ else
+ ret = -EINVAL;
+
+ if (IS_ERR_VALUE(ret))
+ ov_camera_module_pr_debug(cam_mod,
+ "failed with error (%d)\n", ret);
+
+ return ret;
+}
+
+/*--------------------------------------------------------------------------*/
+
+static int ov2710_start_streaming(struct ov_camera_module *cam_mod)
+{
+ int ret = 0;
+
+ ov_camera_module_pr_debug(cam_mod,
+ "active config=%s\n", cam_mod->active_config->name);
+
+ ret = OV2710_g_VTS(cam_mod, &cam_mod->vts_min);
+ if (IS_ERR_VALUE(ret))
+ goto err;
+ ov_camera_module_pr_debug(cam_mod, "=====streaming on ===\n");
+ ret = ov_camera_module_write_reg(cam_mod, 0x3008, 0x02);
+ ret |= ov_camera_module_write_reg(cam_mod, 0x4201, 0x00);
+ ret |= ov_camera_module_write_reg(cam_mod, 0x4202, 0x00);
+
+ if (IS_ERR_VALUE(ret))
+ goto err;
+
+ return 0;
+err:
+ ov_camera_module_pr_err(cam_mod, "failed with error (%d)\n",
+ ret);
+ return ret;
+}
+
+/*--------------------------------------------------------------------------*/
+
+static int ov2710_stop_streaming(struct ov_camera_module *cam_mod)
+{
+ int ret = 0;
+
+ ov_camera_module_pr_debug(cam_mod, "\n");
+ ret = ov_camera_module_write_reg(cam_mod, 0x3008, 0x42);
+ ret |= ov_camera_module_write_reg(cam_mod, 0x4201, 0x00);
+ ret |= ov_camera_module_write_reg(cam_mod, 0x4202, 0x0f);
+
+ if (IS_ERR_VALUE(ret))
+ goto err;
+
+ return 0;
+err:
+ ov_camera_module_pr_err(cam_mod, "failed with error (%d)\n", ret);
+ return ret;
+}
+
+/*--------------------------------------------------------------------------*/
+
+static int ov2710_check_camera_id(struct ov_camera_module *cam_mod)
+{
+ u32 pidh, pidl;
+ int ret = 0;
+
+ ov_camera_module_pr_debug(cam_mod, "\n");
+
+ ret |= ov_camera_module_read_reg(cam_mod, 1, OV2710_PIDH_ADDR, &pidh);
+ ret |= ov_camera_module_read_reg(cam_mod, 1, OV2710_PIDL_ADDR, &pidl);
+ if (IS_ERR_VALUE(ret)) {
+ ov_camera_module_pr_err(cam_mod,
+ "register read failed, camera module powered off?\n");
+ goto err;
+ }
+
+ if ((pidh == OV2710_PIDH_MAGIC) && (pidl == OV2710_PIDL_MAGIC))
+ ov_camera_module_pr_debug(cam_mod,
+ "successfully detected camera ID 0x%02x%02x\n",
+ pidh, pidl);
+ else {
+ ov_camera_module_pr_err(cam_mod,
+ "wrong camera ID, expected 0x%02x%02x, detected 0x%02x%02x\n",
+ OV2710_PIDH_MAGIC, OV2710_PIDL_MAGIC, pidh, pidl);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ return 0;
+err:
+ ov_camera_module_pr_err(cam_mod, "failed with error (%d)\n", ret);
+ return ret;
+}
+
+/* ======================================================================== */
+int ov_camera_2710_module_s_ctrl(
+ struct v4l2_subdev *sd,
+ struct v4l2_control *ctrl)
+{
+ return 0;
+}
+
+/* ======================================================================== */
+
+int ov_camera_2710_module_s_ext_ctrls(
+ struct v4l2_subdev *sd,
+ struct v4l2_ext_controls *ctrls)
+{
+ return 0;
+}
+
+long ov_camera_2710_module_ioctl(struct v4l2_subdev *sd,
+ unsigned int cmd,
+ void *arg)
+{
+ return 0;
+}
+
+/* ======================================================================== */
+/* This part is platform dependent */
+/* ======================================================================== */
+
+static struct v4l2_subdev_core_ops ov2710_camera_module_core_ops = {
+ .g_ctrl = ov_camera_module_g_ctrl,
+ .s_ctrl = ov_camera_module_s_ctrl,
+ .s_ext_ctrls = ov_camera_module_s_ext_ctrls,
+ .s_power = ov_camera_module_s_power,
+ .ioctl = ov_camera_module_ioctl
+};
+
+static struct v4l2_subdev_video_ops ov2710_camera_module_video_ops = {
+ .s_frame_interval = ov_camera_module_s_frame_interval,
+ .s_stream = ov_camera_module_s_stream
+};
+
+static struct v4l2_subdev_pad_ops ov2710_camera_module_pad_ops = {
+ .enum_frame_interval = ov_camera_module_enum_frameintervals,
+ .get_fmt = ov_camera_module_g_fmt,
+ .set_fmt = ov_camera_module_s_fmt,
+};
+
+static struct v4l2_subdev_ops ov2710_camera_module_ops = {
+ .core = &ov2710_camera_module_core_ops,
+ .video = &ov2710_camera_module_video_ops,
+ .pad = &ov2710_camera_module_pad_ops
+};
+
+static struct ov_camera_module ov2710;
+
+static struct ov_camera_module_custom_config ov2710_custom_config = {
+ .start_streaming = ov2710_start_streaming,
+ .stop_streaming = ov2710_stop_streaming,
+ .s_ctrl = ov2710_s_ctrl,
+ .g_ctrl = ov2710_g_ctrl,
+ .s_ext_ctrls = ov2710_s_ext_ctrls,
+ .g_timings = ov2710_g_timings,
+ .set_flip = ov2710_set_flip,
+ .check_camera_id = ov2710_check_camera_id,
+ .configs = ov2710_configs,
+ .num_configs = ARRAY_SIZE(ov2710_configs),
+ .power_up_delays_ms = {5, 30, 30}
+};
+
+static int ov2710_probe(
+ struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ dev_info(&client->dev, "probing...\n");
+
+ ov2710_filltimings(&ov2710_custom_config);
+ v4l2_i2c_subdev_init(&ov2710.sd, client,
+ &ov2710_camera_module_ops);
+
+ ov2710.custom = ov2710_custom_config;
+
+ dev_info(&client->dev, "probing successful\n");
+ return 0;
+}
+
+/* ======================================================================== */
+
+static int ov2710_remove(
+ struct i2c_client *client)
+{
+ struct ov_camera_module *cam_mod = i2c_get_clientdata(client);
+
+ dev_info(&client->dev, "removing device...\n");
+
+ if (!client->adapter)
+ return -ENODEV; /* our client isn't attached */
+
+ ov_camera_module_release(cam_mod);
+
+ dev_info(&client->dev, "removed\n");
+ return 0;
+}
+
+static const struct i2c_device_id ov2710_id[] = {
+ { OV2710_DRIVER_NAME, 0 },
+ { }
+};
+
+static const struct of_device_id ov2710_of_match[] = {
+ {.compatible = "omnivision,ov2710-v4l2-i2c-subdev"},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, ov2710_id);
+
+static struct i2c_driver ov2710_i2c_driver = {
+ .driver = {
+ .name = OV2710_DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = ov2710_of_match
+ },
+ .probe = ov2710_probe,
+ .remove = ov2710_remove,
+ .id_table = ov2710_id,
+};
+
+module_i2c_driver(ov2710_i2c_driver);
+
+MODULE_DESCRIPTION("SoC Camera driver for ov2710");
+MODULE_AUTHOR("Eike Grimpe");
+MODULE_LICENSE("GPL");
+
--- /dev/null
+/*
+ * ov4689 sensor driver
+ *
+ * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd.
+ *
+ * Copyright (C) 2012-2014 Intel Mobile Communications GmbH
+ *
+ * Copyright (C) 2008 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <media/v4l2-subdev.h>
+#include <media/videobuf-core.h>
+#include <linux/slab.h>
+#include "ov_camera_module.h"
+
+#define ov4689_DRIVER_NAME "ov4689"
+
+#define ov4689_AEC_PK_LONG_GAIN_HIGH_REG 0x3508 /* Bit 6-13 */
+#define ov4689_AEC_PK_LONG_GAIN_LOW_REG 0x3509 /* Bits 0 -5 */
+#define ov4689_FETCH_LSB_GAIN(VAL) ((VAL) & 0x00ff)
+#define ov4689_FETCH_MSB_GAIN(VAL) (((VAL) >> 8) & 0xff)
+
+#define ov4689_AEC_PK_LONG_EXPO_3RD_REG 0x3500 /* Exposure Bits 16-19 */
+#define ov4689_AEC_PK_LONG_EXPO_2ND_REG 0x3501 /* Exposure Bits 8-15 */
+#define ov4689_AEC_PK_LONG_EXPO_1ST_REG 0x3502 /* Exposure Bits 0-7 */
+#define ov4689_FETCH_3RD_BYTE_EXP(VAL) (((VAL) >> 12) & 0xF) /* 4 Bits */
+#define ov4689_FETCH_2ND_BYTE_EXP(VAL) (((VAL) >> 4) & 0xFF) /* 8 Bits */
+#define ov4689_FETCH_1ST_BYTE_EXP(VAL) (((VAL) & 0x0F) << 4) /* 4 Bits */
+
+#define ov4689_AEC_GROUP_UPDATE_ADDRESS 0x3208
+#define ov4689_AEC_GROUP_UPDATE_START_DATA 0x00
+#define ov4689_AEC_GROUP_UPDATE_END_DATA 0x10
+#define ov4689_AEC_GROUP_UPDATE_END_LAUNCH 0xA0
+
+#define ov4689_PIDH_ADDR 0x300A
+#define ov4689_PIDL_ADDR 0x300B
+
+#define ov4689_PIDH_MAGIC 0x46
+#define ov4689_PIDL_MAGIC 0x88
+
+#define ov4689_TIMING_VTS_HIGH_REG 0x380e
+#define ov4689_TIMING_VTS_LOW_REG 0x380f
+#define ov4689_TIMING_HTS_HIGH_REG 0x380c
+#define ov4689_TIMING_HTS_LOW_REG 0x380d
+#define ov4689_INTEGRATION_TIME_MARGIN 8
+#define ov4689_FINE_INTG_TIME_MIN 0
+#define ov4689_FINE_INTG_TIME_MAX_MARGIN 0
+#define ov4689_COARSE_INTG_TIME_MIN 16
+#define ov4689_COARSE_INTG_TIME_MAX_MARGIN 4
+#define ov4689_TIMING_X_INC 0x3814
+#define ov4689_TIMING_Y_INC 0x3815
+#define ov4689_HORIZONTAL_START_HIGH_REG 0x3800
+#define ov4689_HORIZONTAL_START_LOW_REG 0x3801
+#define ov4689_VERTICAL_START_HIGH_REG 0x3802
+#define ov4689_VERTICAL_START_LOW_REG 0x3803
+#define ov4689_HORIZONTAL_END_HIGH_REG 0x3804
+#define ov4689_HORIZONTAL_END_LOW_REG 0x3805
+#define ov4689_VERTICAL_END_HIGH_REG 0x3806
+#define ov4689_VERTICAL_END_LOW_REG 0x3807
+#define ov4689_HORIZONTAL_OUTPUT_SIZE_HIGH_REG 0x3808
+#define ov4689_HORIZONTAL_OUTPUT_SIZE_LOW_REG 0x3809
+#define ov4689_VERTICAL_OUTPUT_SIZE_HIGH_REG 0x380a
+#define ov4689_VERTICAL_OUTPUT_SIZE_LOW_REG 0x380b
+#define ov4689_FLIP_REG 0x3820
+#define ov4689_MIRROR_REG 0x3821
+
+#define ov4689_EXT_CLK 24000000
+
+#define ov4689_FULL_SIZE_RESOLUTION_WIDTH 2688
+#define ov4689_BINING_SIZE_RESOLUTION_WIDTH 1280
+
+static struct ov_camera_module ov4689;
+static struct ov_camera_module_custom_config ov4689_custom_config;
+
+/* ======================================================================== */
+/* Base sensor configs */
+/* ======================================================================== */
+
+/* MCLK:24MHz 2688x1520 30fps mipi 4lane 1008Mbps/lane */
+static struct ov_camera_module_reg ov4689_init_tab_2688_1520_30fps[] = {
+/* global setting */
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0103, 0x01},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3638, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0300, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0302, 0x2a},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0303, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0304, 0x03},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x030b, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x030d, 0x1e},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x030e, 0x04},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x030f, 0x01},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0312, 0x01},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x031e, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3000, 0x20},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3002, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3018, 0x32},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3020, 0x93},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3021, 0x03},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3022, 0x01},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3031, 0x0a},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x303f, 0x0c},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3305, 0xf1},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3307, 0x04},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3309, 0x29},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3500, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3501, 0x60},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3502, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3503, 0x04},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3504, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3505, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3506, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3507, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3508, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3509, 0x80},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x350a, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x350b, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x350c, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x350d, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x350e, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x350f, 0x80},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3510, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3511, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3512, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3513, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3514, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3515, 0x80},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3516, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3517, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3518, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3519, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x351a, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x351b, 0x80},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x351c, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x351d, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x351e, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x351f, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3520, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3521, 0x80},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3522, 0x08},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3524, 0x08},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3526, 0x08},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3528, 0x08},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x352a, 0x08},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3602, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3603, 0x40},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3604, 0x02},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3605, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3606, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3607, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3609, 0x12},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x360a, 0x40},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x360c, 0x08},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x360f, 0xe5},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3608, 0x8f},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3611, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3613, 0xf7},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3616, 0x58},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3619, 0x99},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x361b, 0x60},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x361c, 0x7a},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x361e, 0x79},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x361f, 0x02},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3632, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3633, 0x10},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3634, 0x10},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3635, 0x10},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3636, 0x15},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3646, 0x86},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x364a, 0x0b},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3700, 0x17},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3701, 0x22},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3703, 0x10},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x370a, 0x37},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3705, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3706, 0x63},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3709, 0x3c},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x370b, 0x01},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x370c, 0x30},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3710, 0x24},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3711, 0x0c},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3716, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3720, 0x28},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3729, 0x7b},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x372a, 0x84},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x372b, 0xbd},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x372c, 0xbc},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x372e, 0x52},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x373c, 0x0e},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x373e, 0x33},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3743, 0x10},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3744, 0x88},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3745, 0xc0},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x374a, 0x43},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x374c, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x374e, 0x23},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3751, 0x7b},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3752, 0x84},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3753, 0xbd},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3754, 0xbc},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3756, 0x52},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x375c, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3760, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3761, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3762, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3763, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3764, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3767, 0x04},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3768, 0x04},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3769, 0x08},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x376a, 0x08},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x376b, 0x20},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x376c, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x376d, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x376e, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3773, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3774, 0x51},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3776, 0xbd},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3777, 0xbd }
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3781, 0x18},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3783, 0x25},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3798, 0x1b},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3800, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3801, 0x08},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3802, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3803, 0x04},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3804, 0x0a},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3805, 0x97},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3806, 0x05},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3807, 0xfb},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3808, 0x0a},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3809, 0x80},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380a, 0x05},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380b, 0xf0},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380c, 0x0a},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380d, 0x18},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380e, 0x06},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380f, 0x12},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3810, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3811, 0x08},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3812, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3813, 0x04},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3814, 0x01},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3815, 0x01},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3819, 0x01},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3820, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3821, 0x06},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3829, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x382a, 0x01},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x382b, 0x01},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x382d, 0x7f},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3830, 0x04},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3836, 0x01},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3837, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3841, 0x02},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3846, 0x08},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3847, 0x07},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3d85, 0x36},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3d8c, 0x71},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3d8d, 0xcb},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3f0a, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4000, 0xf1},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4001, 0x40},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4002, 0x04},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4003, 0x14},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x400e, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4011, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x401a, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x401b, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x401c, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x401d, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x401f, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4020, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4021, 0x10},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4022, 0x07},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4023, 0xcf},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4024, 0x09},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4025, 0x60},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4026, 0x09},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4027, 0x6f},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4028, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4029, 0x02},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x402a, 0x06},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x402b, 0x04},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x402c, 0x02},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x402d, 0x02},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x402e, 0x0e},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x402f, 0x04},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4302, 0xff},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4303, 0xff},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4304, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4305, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4306, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4308, 0x02},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4500, 0x6c},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4501, 0xc4},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4502, 0x40},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4503, 0x01},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4601, 0xa7},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4800, 0x04},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4813, 0x08},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x481f, 0x40},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4829, 0x78},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4837, 0x10},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4b00, 0x2a},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4b0d, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4d00, 0x04},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4d01, 0x42},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4d02, 0xd1},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4d03, 0x93},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4d04, 0xf5},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4d05, 0xc1},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5000, 0xf3},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5001, 0x11},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5004, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x500a, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x500b, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5032, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5040, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5050, 0x0c},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5500, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5501, 0x10},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5502, 0x01},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5503, 0x0f},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x8000, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x8001, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x8002, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x8003, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x8004, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x8005, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x8006, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x8007, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x8008, 0x00},
+{OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3638, 0x00},
+/* {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0100, 0x01} */
+};
+
+static struct ov_camera_module_config ov4689_configs[] = {
+ {
+ .name = "2688x1520_30fps",
+ .frm_fmt = {
+ .width = 2688,
+ .height = 1520,
+ .code = MEDIA_BUS_FMT_SBGGR10_1X10
+ },
+ .frm_intrvl = {
+ .interval = {
+ .numerator = 1,
+ .denominator = 30
+ }
+ },
+ .auto_exp_enabled = false,
+ .auto_gain_enabled = false,
+ .auto_wb_enabled = false,
+ .reg_table = (void *)ov4689_init_tab_2688_1520_30fps,
+ .reg_table_num_entries =
+ sizeof(ov4689_init_tab_2688_1520_30fps) /
+ sizeof(ov4689_init_tab_2688_1520_30fps[0]),
+ .v_blanking_time_us = 5000,
+ PLTFRM_CAM_ITF_MIPI_CFG(0, 2, 999, ov4689_EXT_CLK)
+ }
+};
+
+static int ov4689_g_VTS(struct ov_camera_module *cam_mod, u32 *vts)
+{
+ u32 msb, lsb;
+ int ret;
+
+ ret = ov_camera_module_read_reg_table(
+ cam_mod,
+ ov4689_TIMING_VTS_HIGH_REG,
+ &msb);
+ if (IS_ERR_VALUE(ret))
+ goto err;
+
+ ret = ov_camera_module_read_reg_table(
+ cam_mod,
+ ov4689_TIMING_VTS_LOW_REG,
+ &lsb);
+ if (IS_ERR_VALUE(ret))
+ goto err;
+
+ *vts = (msb << 8) | lsb;
+
+ return 0;
+err:
+ ov_camera_module_pr_err(cam_mod, "failed with error (%d)\n", ret);
+ return ret;
+}
+
+static int ov4689_auto_adjust_fps(struct ov_camera_module *cam_mod,
+ u32 exp_time)
+{
+ int ret;
+ u32 vts;
+
+ if ((cam_mod->exp_config.exp_time +
+ ov4689_COARSE_INTG_TIME_MAX_MARGIN)
+ > cam_mod->vts_min)
+ vts = cam_mod->exp_config.exp_time +
+ ov4689_COARSE_INTG_TIME_MAX_MARGIN;
+ else
+ vts = cam_mod->vts_min;
+ ret = ov_camera_module_write_reg(cam_mod,
+ ov4689_TIMING_VTS_LOW_REG, vts & 0xFF);
+ ret |= ov_camera_module_write_reg(cam_mod,
+ ov4689_TIMING_VTS_HIGH_REG,
+ (vts >> 8) & 0xFF);
+
+ if (IS_ERR_VALUE(ret))
+ ov_camera_module_pr_err(cam_mod,
+ "failed with error (%d)\n", ret);
+ else
+ ov_camera_module_pr_debug(cam_mod,
+ "updated vts = %d,vts_min=%d\n",
+ vts, cam_mod->vts_min);
+
+ return ret;
+}
+
+static int ov4689_write_aec(struct ov_camera_module *cam_mod)
+{
+ int ret = 0;
+
+ ov_camera_module_pr_debug(cam_mod,
+ "exp_time = %d, gain = %d, flash_mode = %d\n",
+ cam_mod->exp_config.exp_time,
+ cam_mod->exp_config.gain,
+ cam_mod->exp_config.flash_mode);
+
+ /*
+ * if the sensor is already streaming, write to shadow registers,
+ * if the sensor is in SW standby, write to active registers,
+ * if the sensor is off/registers are not writeable, do nothing
+ */
+ if ((cam_mod->state == OV_CAMERA_MODULE_SW_STANDBY) ||
+ (cam_mod->state == OV_CAMERA_MODULE_STREAMING)) {
+ u32 a_gain = cam_mod->exp_config.gain;
+ u32 exp_time = cam_mod->exp_config.exp_time;
+
+ a_gain = a_gain * cam_mod->exp_config.gain_percent / 100;
+
+ if (cam_mod->state == OV_CAMERA_MODULE_STREAMING)
+ ret = ov_camera_module_write_reg(cam_mod,
+ ov4689_AEC_GROUP_UPDATE_ADDRESS,
+ ov4689_AEC_GROUP_UPDATE_START_DATA);
+ if (!IS_ERR_VALUE(ret) && cam_mod->auto_adjust_fps)
+ ret = ov4689_auto_adjust_fps(cam_mod,
+ cam_mod->exp_config.exp_time);
+ ret |= ov_camera_module_write_reg(cam_mod,
+ ov4689_AEC_PK_LONG_GAIN_HIGH_REG,
+ ov4689_FETCH_MSB_GAIN(a_gain));
+ ret |= ov_camera_module_write_reg(cam_mod,
+ ov4689_AEC_PK_LONG_GAIN_LOW_REG,
+ ov4689_FETCH_LSB_GAIN(a_gain));
+ ret = ov_camera_module_write_reg(cam_mod,
+ ov4689_AEC_PK_LONG_EXPO_3RD_REG,
+ ov4689_FETCH_3RD_BYTE_EXP(exp_time));
+ ret |= ov_camera_module_write_reg(cam_mod,
+ ov4689_AEC_PK_LONG_EXPO_2ND_REG,
+ ov4689_FETCH_2ND_BYTE_EXP(exp_time));
+ ret |= ov_camera_module_write_reg(cam_mod,
+ ov4689_AEC_PK_LONG_EXPO_1ST_REG,
+ ov4689_FETCH_1ST_BYTE_EXP(exp_time));
+ if (cam_mod->state == OV_CAMERA_MODULE_STREAMING) {
+ ret = ov_camera_module_write_reg(cam_mod,
+ ov4689_AEC_GROUP_UPDATE_ADDRESS,
+ ov4689_AEC_GROUP_UPDATE_END_DATA);
+ ret = ov_camera_module_write_reg(cam_mod,
+ ov4689_AEC_GROUP_UPDATE_ADDRESS,
+ ov4689_AEC_GROUP_UPDATE_END_LAUNCH);
+ }
+ }
+
+ if (IS_ERR_VALUE(ret))
+ ov_camera_module_pr_err(cam_mod,
+ "failed with error (%d)\n", ret);
+ return ret;
+}
+
+/*--------------------------------------------------------------------------*/
+
+static int ov4689_g_ctrl(struct ov_camera_module *cam_mod, u32 ctrl_id)
+{
+ int ret = 0;
+
+ ov_camera_module_pr_debug(cam_mod, "\n");
+
+ switch (ctrl_id) {
+ case V4L2_CID_GAIN:
+ case V4L2_CID_EXPOSURE:
+ case V4L2_CID_FLASH_LED_MODE:
+ /* nothing to be done here */
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ if (IS_ERR_VALUE(ret))
+ ov_camera_module_pr_debug(cam_mod,
+ "failed with error (%d)\n", ret);
+ return ret;
+}
+
+static int ov4689_filltimings(struct ov_camera_module_custom_config *custom)
+{
+ int i, j;
+ struct ov_camera_module_config *config;
+ struct ov_camera_module_timings *timings;
+ struct ov_camera_module_reg *reg_table;
+ int reg_table_num_entries;
+
+ for (i = 0; i < custom->num_configs; i++) {
+ config = &custom->configs[i];
+ reg_table = config->reg_table;
+ reg_table_num_entries = config->reg_table_num_entries;
+ timings = &config->timings;
+
+ for (j = 0; j < reg_table_num_entries; j++) {
+ switch (reg_table[j].reg) {
+ case ov4689_TIMING_VTS_HIGH_REG:
+ timings->frame_length_lines =
+ reg_table[j].val << 8;
+ break;
+ case ov4689_TIMING_VTS_LOW_REG:
+ timings->frame_length_lines |= reg_table[j].val;
+ break;
+ case ov4689_TIMING_HTS_HIGH_REG:
+ timings->line_length_pck =
+ (reg_table[j].val << 8);
+ break;
+ case ov4689_TIMING_HTS_LOW_REG:
+ timings->line_length_pck |= reg_table[j].val;
+ break;
+ case ov4689_TIMING_X_INC:
+ timings->binning_factor_x =
+ ((reg_table[j].val >> 4) + 1) / 2;
+ if (timings->binning_factor_x == 0)
+ timings->binning_factor_x = 1;
+ break;
+ case ov4689_TIMING_Y_INC:
+ timings->binning_factor_y =
+ ((reg_table[j].val >> 4) + 1) / 2;
+ if (timings->binning_factor_y == 0)
+ timings->binning_factor_y = 1;
+ break;
+ case ov4689_HORIZONTAL_START_HIGH_REG:
+ timings->crop_horizontal_start =
+ reg_table[j].val << 8;
+ break;
+ case ov4689_HORIZONTAL_START_LOW_REG:
+ timings->crop_horizontal_start |=
+ reg_table[j].val;
+ break;
+ case ov4689_VERTICAL_START_HIGH_REG:
+ timings->crop_vertical_start =
+ reg_table[j].val << 8;
+ break;
+ case ov4689_VERTICAL_START_LOW_REG:
+ timings->crop_vertical_start |=
+ reg_table[j].val;
+ break;
+ case ov4689_HORIZONTAL_END_HIGH_REG:
+ timings->crop_horizontal_end =
+ reg_table[j].val << 8;
+ break;
+ case ov4689_HORIZONTAL_END_LOW_REG:
+ timings->crop_horizontal_end |=
+ reg_table[j].val;
+ break;
+ case ov4689_VERTICAL_END_HIGH_REG:
+ timings->crop_vertical_end =
+ reg_table[j].val << 8;
+ break;
+ case ov4689_VERTICAL_END_LOW_REG:
+ timings->crop_vertical_end |= reg_table[j].val;
+ break;
+ case ov4689_HORIZONTAL_OUTPUT_SIZE_HIGH_REG:
+ timings->sensor_output_width =
+ reg_table[j].val << 8;
+ break;
+ case ov4689_HORIZONTAL_OUTPUT_SIZE_LOW_REG:
+ timings->sensor_output_width |=
+ reg_table[j].val;
+ break;
+ case ov4689_VERTICAL_OUTPUT_SIZE_HIGH_REG:
+ timings->sensor_output_height =
+ reg_table[j].val << 8;
+ break;
+ case ov4689_VERTICAL_OUTPUT_SIZE_LOW_REG:
+ timings->sensor_output_height |=
+ reg_table[j].val;
+ break;
+ }
+ }
+
+ timings->vt_pix_clk_freq_hz =
+ config->frm_intrvl.interval.denominator *
+ timings->frame_length_lines *
+ timings->line_length_pck;
+
+ timings->coarse_integration_time_min =
+ ov4689_COARSE_INTG_TIME_MIN;
+ timings->coarse_integration_time_max_margin =
+ ov4689_COARSE_INTG_TIME_MAX_MARGIN;
+
+ /* OV Sensor do not use fine integration time. */
+ timings->fine_integration_time_min = ov4689_FINE_INTG_TIME_MIN;
+ timings->fine_integration_time_max_margin =
+ ov4689_FINE_INTG_TIME_MAX_MARGIN;
+ }
+
+ return 0;
+}
+
+static int ov4689_g_timings(struct ov_camera_module *cam_mod,
+ struct ov_camera_module_timings *timings)
+{
+ int ret = 0;
+
+ if (IS_ERR_OR_NULL(cam_mod->active_config))
+ goto err;
+
+ *timings = cam_mod->active_config->timings;
+
+ if (cam_mod->frm_intrvl_valid)
+ timings->vt_pix_clk_freq_hz =
+ cam_mod->frm_intrvl.interval.denominator
+ * timings->frame_length_lines
+ * timings->line_length_pck;
+ else
+ timings->vt_pix_clk_freq_hz =
+ cam_mod->active_config->frm_intrvl.interval.denominator
+ * timings->frame_length_lines
+ * timings->line_length_pck;
+
+ return ret;
+err:
+ ov_camera_module_pr_err(cam_mod, "failed with error (%d)\n", ret);
+ return ret;
+}
+
+/*--------------------------------------------------------------------------*/
+
+static int ov4689_set_flip(
+ struct ov_camera_module *cam_mod,
+ struct pltfrm_camera_module_reg reglist[],
+ int len)
+{
+ int i, mode = 0;
+ u16 match_reg[2];
+
+ mode = ov_camera_module_get_flip_mirror(cam_mod);
+ if (mode == -1) {
+ ov_camera_module_pr_info(cam_mod,
+ "dts don't set flip, return!\n");
+ return 0;
+ }
+
+ if (!IS_ERR_OR_NULL(cam_mod->active_config)) {
+ switch (cam_mod->active_config->frm_fmt.width) {
+ case ov4689_FULL_SIZE_RESOLUTION_WIDTH:
+ if (mode == OV_FLIP_BIT_MASK) {
+ match_reg[0] = 0x06;
+ match_reg[1] = 0x00;
+ } else if (mode == OV_MIRROR_BIT_MASK) {
+ match_reg[0] = 0x00;
+ match_reg[1] = 0x06;
+ } else if (mode == (OV_MIRROR_BIT_MASK |
+ OV_FLIP_BIT_MASK)) {
+ match_reg[0] = 0x06;
+ match_reg[1] = 0x06;
+ } else {
+ match_reg[0] = 0x00;
+ match_reg[1] = 0x00;
+ }
+ break;
+ case ov4689_BINING_SIZE_RESOLUTION_WIDTH:
+ if (mode == OV_FLIP_BIT_MASK) {
+ match_reg[0] = 0x16;
+ match_reg[1] = 0x01;
+ } else if (mode == OV_MIRROR_BIT_MASK) {
+ match_reg[0] = 0x16;
+ match_reg[1] = 0x07;
+ } else if (mode == (OV_MIRROR_BIT_MASK |
+ OV_FLIP_BIT_MASK)) {
+ match_reg[0] = 0x16;
+ match_reg[1] = 0x07;
+ } else {
+ match_reg[0] = 0x10;
+ match_reg[1] = 0x01;
+ }
+ break;
+ default:
+ return 0;
+ }
+
+ for (i = len; i > 0; i--) {
+ if (reglist[i].reg == ov4689_FLIP_REG)
+ reglist[i].val = match_reg[0];
+ else if (reglist[i].reg == ov4689_MIRROR_REG)
+ reglist[i].val = match_reg[1];
+ }
+ }
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------*/
+
+static int ov4689_s_ctrl(struct ov_camera_module *cam_mod, u32 ctrl_id)
+{
+ int ret = 0;
+
+ ov_camera_module_pr_debug(cam_mod, "\n");
+
+ switch (ctrl_id) {
+ case V4L2_CID_GAIN:
+ case V4L2_CID_EXPOSURE:
+ ret = ov4689_write_aec(cam_mod);
+ break;
+ case V4L2_CID_FLASH_LED_MODE:
+ /* nothing to be done here */
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ if (IS_ERR_VALUE(ret))
+ ov_camera_module_pr_debug(cam_mod,
+ "failed with error (%d) 0x%x\n", ret, ctrl_id);
+ return ret;
+}
+
+/*--------------------------------------------------------------------------*/
+
+static int ov4689_s_ext_ctrls(struct ov_camera_module *cam_mod,
+ struct ov_camera_module_ext_ctrls *ctrls)
+{
+ int ret = 0;
+
+ /* Handles only exposure and gain together special case. */
+ if (ctrls->count == 1)
+ ret = ov4689_s_ctrl(cam_mod, ctrls->ctrls[0].id);
+ else if ((ctrls->count == 3) &&
+ ((ctrls->ctrls[0].id == V4L2_CID_GAIN &&
+ ctrls->ctrls[1].id == V4L2_CID_EXPOSURE) ||
+ (ctrls->ctrls[1].id == V4L2_CID_GAIN &&
+ ctrls->ctrls[0].id == V4L2_CID_EXPOSURE)))
+ ret = ov4689_write_aec(cam_mod);
+ else
+ ret = -EINVAL;
+
+ if (IS_ERR_VALUE(ret))
+ ov_camera_module_pr_debug(cam_mod,
+ "failed with error (%d)\n", ret);
+ return ret;
+}
+
+/*--------------------------------------------------------------------------*/
+
+static int ov4689_start_streaming(struct ov_camera_module *cam_mod)
+{
+ int ret = 0;
+
+ ov_camera_module_pr_debug(cam_mod,
+ "active config=%s\n", cam_mod->active_config->name);
+
+ ret = ov4689_g_VTS(cam_mod, &cam_mod->vts_min);
+ if (IS_ERR_VALUE(ret))
+ goto err;
+
+ if (IS_ERR_VALUE(ov_camera_module_write_reg(cam_mod, 0x0100, 1)))
+ goto err;
+
+ msleep(25);
+
+ return 0;
+err:
+ ov_camera_module_pr_err(cam_mod, "failed with error (%d)\n",
+ ret);
+ return ret;
+}
+
+/*--------------------------------------------------------------------------*/
+
+static int ov4689_stop_streaming(struct ov_camera_module *cam_mod)
+{
+ int ret = 0;
+
+ ov_camera_module_pr_debug(cam_mod, "\n");
+
+ ret = ov_camera_module_write_reg(cam_mod, 0x0100, 0);
+ if (IS_ERR_VALUE(ret))
+ goto err;
+
+ msleep(25);
+
+ return 0;
+err:
+ ov_camera_module_pr_err(cam_mod, "failed with error (%d)\n", ret);
+ return ret;
+}
+
+/*--------------------------------------------------------------------------*/
+static int ov4689_check_camera_id(struct ov_camera_module *cam_mod)
+{
+ u32 pidh, pidl;
+ int ret = 0;
+
+ ov_camera_module_pr_debug(cam_mod, "\n");
+
+ ret |= ov_camera_module_read_reg(cam_mod, 1, ov4689_PIDH_ADDR, &pidh);
+ ret |= ov_camera_module_read_reg(cam_mod, 1, ov4689_PIDL_ADDR, &pidl);
+ if (IS_ERR_VALUE(ret)) {
+ ov_camera_module_pr_err(cam_mod,
+ "register read failed, camera module powered off?\n");
+ goto err;
+ }
+
+ if ((pidh == ov4689_PIDH_MAGIC) && (pidl == ov4689_PIDL_MAGIC))
+ ov_camera_module_pr_debug(cam_mod,
+ "successfully detected camera ID 0x%02x%02x\n",
+ pidh, pidl);
+ else {
+ ov_camera_module_pr_err(cam_mod,
+ "wrong camera ID, expected 0x%02x%02x, detected 0x%02x%02x\n",
+ ov4689_PIDH_MAGIC, ov4689_PIDL_MAGIC, pidh, pidl);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ return 0;
+err:
+ ov_camera_module_pr_err(cam_mod, "failed with error (%d)\n", ret);
+ return ret;
+}
+
+/* ======================================================================== */
+/* This part is platform dependent */
+/* ======================================================================== */
+
+static struct v4l2_subdev_core_ops ov4689_camera_module_core_ops = {
+ .g_ctrl = ov_camera_module_g_ctrl,
+ .s_ctrl = ov_camera_module_s_ctrl,
+ .s_ext_ctrls = ov_camera_module_s_ext_ctrls,
+ .s_power = ov_camera_module_s_power,
+ .ioctl = ov_camera_module_ioctl
+};
+
+static struct v4l2_subdev_video_ops ov4689_camera_module_video_ops = {
+ .s_frame_interval = ov_camera_module_s_frame_interval,
+ .s_stream = ov_camera_module_s_stream
+};
+
+static struct v4l2_subdev_pad_ops ov4689_camera_module_pad_ops = {
+ .enum_frame_interval = ov_camera_module_enum_frameintervals,
+ .get_fmt = ov_camera_module_g_fmt,
+ .set_fmt = ov_camera_module_s_fmt,
+};
+
+static struct v4l2_subdev_ops ov4689_camera_module_ops = {
+ .core = &ov4689_camera_module_core_ops,
+ .video = &ov4689_camera_module_video_ops,
+ .pad = &ov4689_camera_module_pad_ops
+};
+
+static struct ov_camera_module_custom_config ov4689_custom_config = {
+ .start_streaming = ov4689_start_streaming,
+ .stop_streaming = ov4689_stop_streaming,
+ .s_ctrl = ov4689_s_ctrl,
+ .s_ext_ctrls = ov4689_s_ext_ctrls,
+ .g_ctrl = ov4689_g_ctrl,
+ .g_timings = ov4689_g_timings,
+ .check_camera_id = ov4689_check_camera_id,
+ .set_flip = ov4689_set_flip,
+ .configs = ov4689_configs,
+ .num_configs = ARRAY_SIZE(ov4689_configs),
+ .power_up_delays_ms = {5, 20, 0}
+};
+
+static int ov4689_probe(
+ struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ dev_info(&client->dev, "probing...\n");
+
+ ov4689_filltimings(&ov4689_custom_config);
+ v4l2_i2c_subdev_init(&ov4689.sd, client, &ov4689_camera_module_ops);
+
+ ov4689.custom = ov4689_custom_config;
+
+ dev_info(&client->dev, "probing successful\n");
+ return 0;
+}
+
+static int ov4689_remove(struct i2c_client *client)
+{
+ struct ov_camera_module *cam_mod = i2c_get_clientdata(client);
+
+ dev_info(&client->dev, "removing device...\n");
+
+ if (!client->adapter)
+ return -ENODEV; /* our client isn't attached */
+
+ ov_camera_module_release(cam_mod);
+
+ dev_info(&client->dev, "removed\n");
+ return 0;
+}
+
+static const struct i2c_device_id ov4689_id[] = {
+ { ov4689_DRIVER_NAME, 0 },
+ { }
+};
+
+static const struct of_device_id ov4689_of_match[] = {
+ {.compatible = "omnivision,ov4689-v4l2-i2c-subdev"},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, ov4689_id);
+
+static struct i2c_driver ov4689_i2c_driver = {
+ .driver = {
+ .name = ov4689_DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = ov4689_of_match
+ },
+ .probe = ov4689_probe,
+ .remove = ov4689_remove,
+ .id_table = ov4689_id,
+};
+
+module_i2c_driver(ov4689_i2c_driver);
+
+MODULE_DESCRIPTION("SoC Camera driver for ov4689");
+MODULE_AUTHOR("George");
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * drivers/media/i2c/soc_camera/xgold/ov8858.c
+ *
+ * ov8858 sensor driver
+ *
+ * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd.
+ *
+ * Copyright (C) 2012-2014 Intel Mobile Communications GmbH
+ *
+ * Copyright (C) 2008 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ * Note:
+ * 07/01/2014: new implementation using v4l2-subdev
+ * instead of v4l2-int-device.
+ */
+
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <media/v4l2-subdev.h>
+#include <media/videobuf-core.h>
+#include <linux/slab.h>
+#include "ov_camera_module.h"
+
+#define ov8858_DRIVER_NAME "ov8858"
+
+#define ov8858_FETCH_LSB_GAIN(VAL) ((VAL) & 0x00ff)
+#define ov8858_FETCH_MSB_GAIN(VAL) (((VAL) >> 8) & 0xff)
+#define ov8858_AEC_PK_LONG_GAIN_HIGH_REG 0x3508 /* Bit 6-13 */
+#define ov8858_AEC_PK_LONG_GAIN_LOW_REG 0x3509 /* Bits 0 -5 */
+
+#define ov8858_AEC_PK_LONG_EXPO_3RD_REG 0x3500 /* Exposure Bits 16-19 */
+#define ov8858_AEC_PK_LONG_EXPO_2ND_REG 0x3501 /* Exposure Bits 8-15 */
+#define ov8858_AEC_PK_LONG_EXPO_1ST_REG 0x3502 /* Exposure Bits 0-7 */
+
+#define ov8858_AEC_GROUP_UPDATE_ADDRESS 0x3208
+#define ov8858_AEC_GROUP_UPDATE_START_DATA 0x00
+#define ov8858_AEC_GROUP_UPDATE_END_DATA 0x10
+#define ov8858_AEC_GROUP_UPDATE_END_LAUNCH 0xA0
+
+#define ov8858_FETCH_3RD_BYTE_EXP(VAL) (((VAL) >> 16) & 0xF) /* 4 Bits */
+#define ov8858_FETCH_2ND_BYTE_EXP(VAL) (((VAL) >> 8) & 0xFF) /* 8 Bits */
+#define ov8858_FETCH_1ST_BYTE_EXP(VAL) ((VAL) & 0xFF) /* 8 Bits */
+
+#define ov8858_PIDH_ADDR 0x300B
+#define ov8858_PIDL_ADDR 0x300C
+
+#define ov8858_TIMING_VTS_HIGH_REG 0x380e
+#define ov8858_TIMING_VTS_LOW_REG 0x380f
+#define ov8858_TIMING_HTS_HIGH_REG 0x380c
+#define ov8858_TIMING_HTS_LOW_REG 0x380d
+#define ov8858_INTEGRATION_TIME_MARGIN 8
+#define ov8858_FINE_INTG_TIME_MIN 0
+#define ov8858_FINE_INTG_TIME_MAX_MARGIN 0
+#define ov8858_COARSE_INTG_TIME_MIN 16
+#define ov8858_COARSE_INTG_TIME_MAX_MARGIN 4
+#define ov8858_TIMING_X_INC 0x3814
+#define ov8858_TIMING_Y_INC 0x3815
+#define ov8858_HORIZONTAL_START_HIGH_REG 0x3800
+#define ov8858_HORIZONTAL_START_LOW_REG 0x3801
+#define ov8858_VERTICAL_START_HIGH_REG 0x3802
+#define ov8858_VERTICAL_START_LOW_REG 0x3803
+#define ov8858_HORIZONTAL_END_HIGH_REG 0x3804
+#define ov8858_HORIZONTAL_END_LOW_REG 0x3805
+#define ov8858_VERTICAL_END_HIGH_REG 0x3806
+#define ov8858_VERTICAL_END_LOW_REG 0x3807
+#define ov8858_HORIZONTAL_OUTPUT_SIZE_HIGH_REG 0x3808
+#define ov8858_HORIZONTAL_OUTPUT_SIZE_LOW_REG 0x3809
+#define ov8858_VERTICAL_OUTPUT_SIZE_HIGH_REG 0x380a
+#define ov8858_VERTICAL_OUTPUT_SIZE_LOW_REG 0x380b
+#define ov8858_FLIP_REG 0x3820
+#define ov8858_MIRROR_REG 0x3821
+
+#define ov8858_EXT_CLK 26000000
+
+#define ov8858_FULL_SIZE_RESOLUTION_WIDTH 3264
+#define ov8858_BINING_SIZE_RESOLUTION_WIDTH 1632
+#define ov8858_VIDEO_SIZE_RESOLUTION_WIDTH 3200
+
+#define ov8858_EXP_VALID_FRAMES 4
+/* High byte of product ID */
+#define ov8858_PIDH_MAGIC 0x88
+/* Low byte of product ID */
+#define ov8858_PIDL_MAGIC 0x58
+
+bool is_R1A_module;
+
+#define BG_RATIO_TYPICAL 0x129
+#define RG_RATIO_TYPICAL 0x11f
+
+struct ov8858_otp_struct {
+ int otp_en;
+ int flag;
+ int module_integrator_id;
+ int lens_id;
+ int production_year;
+ int production_month;
+ int production_day;
+ int rg_ratio;
+ int bg_ratio;
+ int lenc[240];
+ int checksum;
+ int VCM_start;
+ int VCM_end;
+ int VCM_dir;
+ int R_gain;
+ int G_gain;
+ int B_gain;
+};
+
+static struct ov8858_otp_struct *otp_ptr;
+static struct ov_camera_module ov8858;
+static struct ov_camera_module_custom_config ov8858_custom_config;
+
+/* ======================================================================== */
+/* Base sensor configs */
+/* ======================================================================== */
+
+/* MCLK:26MHz 3264x2448 18fps mipi 4lane 481Mbps/lane */
+static struct ov_camera_module_reg
+ ov8858_init_tab_3264_2448_18fps[] = {
+ /* global setting */
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0103, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0100, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0300, 0x05},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0301, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0302, 0x94},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0303, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0304, 0x03},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0305, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0306, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x030a, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x030b, 0x05},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x030c, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x030e, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x030d, 0x6f},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x030f, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0312, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x031e, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3033, 0x24},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3600, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3601, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3602, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3603, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3604, 0x22},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3605, 0x20},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3606, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3607, 0x20},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3608, 0x11},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3609, 0x28},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x360a, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x360b, 0x05},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x360c, 0xd4},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x360d, 0x40},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x360e, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x360f, 0x20},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3610, 0x07},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3611, 0x20},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3612, 0x88},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3613, 0x80},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3614, 0x58},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3615, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3616, 0x4a},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3617, 0x40},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3618, 0x5a},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3619, 0x70},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x361a, 0x99},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x361b, 0x0a},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x361c, 0x07},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x361d, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x361e, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x361f, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3638, 0xff},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3633, 0x0f},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3634, 0x0f},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3635, 0x0f},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3636, 0x12},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3645, 0x13},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3646, 0x83},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x364a, 0x07},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3015, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3018, 0x72},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3020, 0x93},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3022, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3031, 0x0a},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3034, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3106, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3305, 0xf1},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3308, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3309, 0x28},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x330a, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x330b, 0x20},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x330c, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x330d, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x330e, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x330f, 0x40},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3307, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3500, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3501, 0x4d},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3502, 0x40},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3503, 0x80},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3505, 0x80},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3508, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3509, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x350c, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x350d, 0x80},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3510, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3511, 0x02},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3512, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3700, 0x30},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3701, 0x18},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3702, 0x50},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3703, 0x32},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3704, 0x28},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3705, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3706, 0x82},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3707, 0x08},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3708, 0x48},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3709, 0x66},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x370a, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x370b, 0x82},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x370c, 0x07},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3718, 0x14},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3719, 0x31},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3712, 0x44},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3714, 0x24},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x371e, 0x31},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x371f, 0x7f},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3720, 0x0a},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3721, 0x0a},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3724, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3725, 0x02},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3726, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3728, 0x0a},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3729, 0x03},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x372a, 0x06},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x372b, 0xa6},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x372c, 0xa6},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x372d, 0xa6},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x372e, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x372f, 0x20},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3730, 0x02},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3731, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3732, 0x28},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3733, 0x10},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3734, 0x40},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3736, 0x30},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x373a, 0x0a},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x373b, 0x0b},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x373c, 0x14},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x373e, 0x06},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3750, 0x0a},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3751, 0x0e},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3755, 0x10},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3758, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3759, 0x4c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x375a, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x375b, 0x26},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x375c, 0x20},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x375d, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x375e, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x375f, 0x28},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3768, 0x22},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3769, 0x44},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x376a, 0x44},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3761, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3762, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3763, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3766, 0xff},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x376b, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3772, 0x46},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3773, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3774, 0x2c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3775, 0x13},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3776, 0x08},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3777, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3778, 0x17},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37a0, 0x88},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37a1, 0x7a},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37a2, 0x7a},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37a3, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37a4, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37a5, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37a6, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37a7, 0x88},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37a8, 0x98},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37a9, 0x98},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3760, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x376f, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37aa, 0x88},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37ab, 0x5c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37ac, 0x5c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37ad, 0x55},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37ae, 0x19},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37af, 0x19},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37b0, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37b1, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37b2, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37b3, 0x84},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37b4, 0x84},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37b5, 0x60},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37b6, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37b7, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37b8, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37b9, 0xff},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3800, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3801, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3802, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3803, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3804, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3805, 0xd3},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3806, 0x09},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3807, 0xa3},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3808, 0x06},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3809, 0x60},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380a, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380b, 0xc8},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380c, 0x0b},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380d, 0x64},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380e, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380f, 0xdc},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3810, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3811, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3813, 0x02},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3814, 0x03},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3815, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3820, 0x06},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3821, 0x40},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x382a, 0x03},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x382b, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3830, 0x08},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3836, 0x02},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3837, 0x18},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3841, 0xff},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3846, 0x48},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3d85, 0x16},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3d8c, 0x73},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3d8d, 0xde},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3f08, 0x10},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3f0a, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4000, 0xf1},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4001, 0x10},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4005, 0x10},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4002, 0x27},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4009, 0x81},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x400b, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4011, 0x20},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x401b, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x401d, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4020, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4021, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4022, 0x06},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4023, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4024, 0x0f},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4025, 0x2a},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4026, 0x0f},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4027, 0x2b},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4028, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4029, 0x02},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x402a, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x402b, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x402c, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x402d, 0x02},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x402e, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x402f, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x401f, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4034, 0x3f},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x403d, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4300, 0xff},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4301, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4302, 0x0f},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4316, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4500, 0x58},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4503, 0x18},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4600, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4601, 0xcb},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x481f, 0x32},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4821, 0x5f},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4837, 0x21},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4850, 0x10},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4851, 0x32},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4b00, 0x2a},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4b0d, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4d00, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4d01, 0x18},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4d02, 0xc3},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4d03, 0xff},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4d04, 0xff},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4d05, 0xff},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5000, 0xfe},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5001, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5002, 0x08},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5003, 0x20},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5046, 0x12},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5780, 0x3e},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5781, 0x0f},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5782, 0x44},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5783, 0x02},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5784, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5785, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5786, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5787, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5788, 0x02},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5789, 0x0f},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x578a, 0xfd},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x578b, 0xf5},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x578c, 0xf5},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x578d, 0x03},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x578e, 0x08},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x578f, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5790, 0x08},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5791, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5792, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5793, 0x52},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5794, 0xa3},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5871, 0x0d},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5870, 0x18},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x586e, 0x10},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x586f, 0x08},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x58f8, 0x3d},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5901, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5b00, 0x02},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5b01, 0x10},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5b02, 0x03},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5b03, 0xcf},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5b05, 0x6c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5e00, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5e01, 0x41},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x382d, 0x7f},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4825, 0x3a},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4826, 0x40},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4808, 0x25},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3763, 0x18},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3768, 0xcc},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x470b, 0x28},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4202, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x400d, 0x10},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4040, 0x07},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x403e, 0x08},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4041, 0xc6},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3007, 0x80},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x400a, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4500, 0x58},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3021, 0x23},
+ /* @@ SIZE_3264X2448_15FPS_MIPI_4LANE based on R2A_EN_AM22 version db */
+ /* ;;pll2_VCO= 721.5, SYSclk=144.3, Dac_clk =360.75 */
+ /* ;;pll1_VCO= 962, pll_MIPIclk=481Mbps */
+ /* mipi_Pclk =60.125, Sclk1=120.25 */
+ /* ;;fps=15, 10bit,4lane, Vblanking=7.251ms */
+ /* update on 2015/06/25.*/
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3808, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3809, 0xc0},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380a, 0x09},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380b, 0x90},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380c, 0x0d},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380d, 0xa0},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380e, 0x0a},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380f, 0xbc},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3814, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3821, 0x46},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x382a, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x382d, 0xff},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3830, 0x06},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3836, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3f0a, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4001, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4022, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4023, 0x60},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4025, 0x36},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4027, 0x37},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x402b, 0x08},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x402f, 0x08},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4500, 0x58},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4600, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4601, 0x97}
+};
+
+static const struct ov_camera_module_reg
+ ov8858_init_tab_1632_1224_30fps_R1A[] = {
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0103, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0100, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0100, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0100, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0100, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0302, 0x1e},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0303, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0304, 0x03},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x030e, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x030f, 0x09},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0312, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x031e, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3600, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3601, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3602, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3603, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3604, 0x22},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3605, 0x30},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3606, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3607, 0x20},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3608, 0x11},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3609, 0x28},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x360a, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x360b, 0x06},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x360c, 0xdc},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x360d, 0x40},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x360e, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x360f, 0x20},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3610, 0x07},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3611, 0x20},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3612, 0x88},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3613, 0x80},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3614, 0x58},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3615, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3616, 0x4a},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3617, 0xb0},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3618, 0x56},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3619, 0x70},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x361a, 0x99},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x361b, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x361c, 0x07},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x361d, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x361e, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x361f, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3638, 0xff},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3633, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3634, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3635, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3636, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3645, 0x13},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3646, 0x83},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x364a, 0x07},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3015, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3018, 0x32},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3020, 0x93},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3022, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3031, 0x0a},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3034, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3106, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3305, 0xf1},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3308, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3309, 0x28},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x330a, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x330b, 0x20},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x330c, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x330d, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x330e, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x330f, 0x40},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3307, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3500, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3501, 0x4d},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3502, 0x40},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3503, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3505, 0x80},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3508, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3509, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x350c, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x350d, 0x80},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3510, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3511, 0x02},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3512, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3700, 0x18},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3701, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3702, 0x28},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3703, 0x19},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3704, 0x14},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3705, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3706, 0x35},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3707, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3708, 0x24},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3709, 0x33},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x370a, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x370b, 0xb5},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x370c, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3718, 0x12},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3719, 0x31},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3712, 0x42},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3714, 0x24},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x371e, 0x19},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x371f, 0x40},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3720, 0x05},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3721, 0x05},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3724, 0x06},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3725, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3726, 0x06},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3728, 0x05},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3729, 0x02},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x372a, 0x03},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x372b, 0x53},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x372c, 0xa3},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x372d, 0x53},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x372e, 0x06},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x372f, 0x10},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3730, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3731, 0x06},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3732, 0x14},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3733, 0x10},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3734, 0x40},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3736, 0x20},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x373a, 0x05},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x373b, 0x06},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x373c, 0x0a},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x373e, 0x03},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3755, 0x10},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3758, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3759, 0x4c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x375a, 0x06},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x375b, 0x13},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x375c, 0x20},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x375d, 0x02},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x375e, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x375f, 0x14},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3768, 0x22},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3769, 0x44},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x376a, 0x44},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3761, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3762, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3763, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3766, 0xff},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x376b, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3772, 0x23},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3773, 0x02},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3774, 0x16},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3775, 0x12},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3776, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3777, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3778, 0x1b},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37a0, 0x44},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37a1, 0x3d},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37a2, 0x3d},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37a3, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37a4, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37a5, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37a6, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37a7, 0x44},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37a8, 0x4c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37a9, 0x4c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3760, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x376f, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37aa, 0x44},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37ab, 0x2e},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37ac, 0x2e},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37ad, 0x33},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37ae, 0x0d},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37af, 0x0d},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37b0, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37b1, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37b2, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37b3, 0x42},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37b4, 0x42},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37b5, 0x33},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37b6, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37b7, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37b8, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37b9, 0xff},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3800, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3801, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3802, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3803, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3804, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3805, 0xd3},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3806, 0x09},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3807, 0xa3},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3808, 0x06},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3809, 0x60},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380a, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380b, 0xc8},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380c, 0x07},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380d, 0x88},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380e, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380f, 0xdc},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3810, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3811, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3813, 0x02},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3814, 0x03},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3815, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3820, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3821, 0x67},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x382a, 0x03},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x382b, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3830, 0x08},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3836, 0x02},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3837, 0x18},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3841, 0xff},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3846, 0x48},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3d85, 0x14},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3f08, 0x08},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3f0a, 0x80},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4000, 0xf1},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4001, 0x10},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4005, 0x10},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4002, 0x27},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4009, 0x81},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x400b, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x401b, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x401d, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4020, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4021, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4022, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4023, 0xb9},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4024, 0x05},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4025, 0x2a},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4026, 0x05},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4027, 0x2b},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4028, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4029, 0x02},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x402a, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x402b, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x402c, 0x02},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x402d, 0x02},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x402e, 0x08},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x402f, 0x02},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x401f, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4034, 0x3f},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x403d, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4300, 0xff},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4301, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4302, 0x0f},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4316, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4500, 0x38},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4503, 0x18},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4600, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4601, 0xcb},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x481f, 0x32},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4837, 0x16},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4850, 0x10},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4851, 0x32},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4b00, 0x2a},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4b0d, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4d00, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4d01, 0x18},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4d02, 0xc3},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4d03, 0xff},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4d04, 0xff},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4d05, 0xff},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5000, 0x7e},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5001, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5002, 0x08},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5003, 0x20},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5046, 0x12},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5901, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5e00, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5e01, 0x41},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x382d, 0x7f},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4825, 0x3a},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4826, 0x40},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4808, 0x25},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x030e, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x030f, 0x09},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0312, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3015, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3501, 0x4d},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3502, 0x40},
+ /* {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3508, 0x04}, */
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3706, 0x35},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x370a, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x370b, 0xb5},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3778, 0x1b},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3808, 0x06},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3809, 0x60},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380a, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380b, 0xc8},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380c, 0x07},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380d, 0x88},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380e, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380f, 0xdc},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3814, 0x03},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3821, 0x67},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x382a, 0x03},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3830, 0x08},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3836, 0x02},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3f0a, 0x80},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4001, 0x10},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4022, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4023, 0xb9},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4024, 0x05},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4025, 0x2a},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4026, 0x05},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4027, 0x2b},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x402b, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x402e, 0x08},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4500, 0x38},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4600, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4601, 0xcb},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x382d, 0x7f}
+};
+
+static const struct ov_camera_module_reg
+ ov8858_init_tab_3264_2448_15fps_R1A[] = {
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0103, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0100, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0100, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0100, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0100, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0302, 0x1e},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0303, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0304, 0x03},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x030e, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x030f, 0x09},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0312, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x031e, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3600, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3601, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3602, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3603, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3604, 0x22},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3605, 0x30},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3606, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3607, 0x20},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3608, 0x11},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3609, 0x28},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x360a, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x360b, 0x06},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x360c, 0xdc},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x360d, 0x40},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x360e, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x360f, 0x20},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3610, 0x07},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3611, 0x20},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3612, 0x88},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3613, 0x80},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3614, 0x58},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3615, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3616, 0x4a},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3617, 0xb0},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3618, 0x56},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3619, 0x70},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x361a, 0x99},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x361b, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x361c, 0x07},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x361d, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x361e, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x361f, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3638, 0xff},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3633, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3634, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3635, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3636, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3645, 0x13},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3646, 0x83},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x364a, 0x07},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3015, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3018, 0x32},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3020, 0x93},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3022, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3031, 0x0a},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3034, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3106, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3305, 0xf1},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3308, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3309, 0x28},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x330a, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x330b, 0x20},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x330c, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x330d, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x330e, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x330f, 0x40},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3307, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3500, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3501, 0x4d},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3502, 0x40},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3503, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3505, 0x80},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3508, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3509, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x350c, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x350d, 0x80},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3510, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3511, 0x02},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3512, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3700, 0x18},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3701, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3702, 0x28},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3703, 0x19},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3704, 0x14},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3705, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3706, 0x35},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3707, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3708, 0x24},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3709, 0x33},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x370a, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x370b, 0xb5},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x370c, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3718, 0x12},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3719, 0x31},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3712, 0x42},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3714, 0x24},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x371e, 0x19},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x371f, 0x40},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3720, 0x05},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3721, 0x05},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3724, 0x06},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3725, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3726, 0x06},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3728, 0x05},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3729, 0x02},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x372a, 0x03},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x372b, 0x53},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x372c, 0xa3},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x372d, 0x53},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x372e, 0x06},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x372f, 0x10},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3730, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3731, 0x06},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3732, 0x14},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3733, 0x10},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3734, 0x40},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3736, 0x20},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x373a, 0x05},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x373b, 0x06},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x373c, 0x0a},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x373e, 0x03},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3755, 0x10},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3758, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3759, 0x4c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x375a, 0x06},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x375b, 0x13},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x375c, 0x20},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x375d, 0x02},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x375e, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x375f, 0x14},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3768, 0x22},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3769, 0x44},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x376a, 0x44},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3761, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3762, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3763, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3766, 0xff},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x376b, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3772, 0x23},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3773, 0x02},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3774, 0x16},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3775, 0x12},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3776, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3777, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3778, 0x1b},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37a0, 0x44},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37a1, 0x3d},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37a2, 0x3d},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37a3, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37a4, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37a5, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37a6, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37a7, 0x44},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37a8, 0x4c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37a9, 0x4c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3760, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x376f, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37aa, 0x44},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37ab, 0x2e},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37ac, 0x2e},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37ad, 0x33},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37ae, 0x0d},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37af, 0x0d},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37b0, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37b1, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37b2, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37b3, 0x42},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37b4, 0x42},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37b5, 0x33},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37b6, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37b7, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37b8, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x37b9, 0xff},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3800, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3801, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3802, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3803, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3804, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3805, 0xd3},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3806, 0x09},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3807, 0xa3},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3808, 0x06},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3809, 0x60},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380a, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380b, 0xc8},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380c, 0x07},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380d, 0x88},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380e, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380f, 0xdc},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3810, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3811, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3813, 0x02},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3814, 0x03},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3815, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3820, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3821, 0x67},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x382a, 0x03},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x382b, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3830, 0x08},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3836, 0x02},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3837, 0x18},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3841, 0xff},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3846, 0x48},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3d85, 0x14},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3f08, 0x08},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3f0a, 0x80},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4000, 0xf1},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4001, 0x10},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4005, 0x10},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4002, 0x27},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4009, 0x81},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x400b, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x401b, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x401d, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4020, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4021, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4022, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4023, 0xb9},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4024, 0x05},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4025, 0x2a},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4026, 0x05},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4027, 0x2b},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4028, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4029, 0x02},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x402a, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x402b, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x402c, 0x02},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x402d, 0x02},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x402e, 0x08},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x402f, 0x02},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x401f, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4034, 0x3f},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x403d, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4300, 0xff},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4301, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4302, 0x0f},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4316, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4500, 0x38},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4503, 0x18},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4600, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4601, 0xcb},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x481f, 0x32},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4837, 0x16},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4850, 0x10},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4851, 0x32},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4b00, 0x2a},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4b0d, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4d00, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4d01, 0x18},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4d02, 0xc3},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4d03, 0xff},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4d04, 0xff},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4d05, 0xff},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5000, 0x7e},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5001, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5002, 0x08},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5003, 0x20},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5046, 0x12},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5901, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5e00, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x5e01, 0x41},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x382d, 0x7f},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4825, 0x3a},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4826, 0x40},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4808, 0x25},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x030e, 0x02},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x030f, 0x04},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x0312, 0x03},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3015, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3501, 0x9a},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3502, 0x20},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3706, 0x6a},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x370a, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x370b, 0x6a},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3778, 0x32},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3808, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3809, 0xc0},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380a, 0x09},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380b, 0x90},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380c, 0x07},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380d, 0x94},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380e, 0x09},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x380f, 0xaa},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3814, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3821, 0x46},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x382a, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3830, 0x06},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3836, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x3f0a, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4001, 0x00},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4022, 0x0b},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4023, 0xc3},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4024, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4025, 0x36},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4026, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4027, 0x37},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x402b, 0x08},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x402e, 0x0c},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4500, 0x58},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4600, 0x01},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x4601, 0x97},
+ {OV_CAMERA_MODULE_REG_TYPE_DATA, 0x382d, 0xff}
+};
+
+/* ======================================================================== */
+static struct ov_camera_module_config ov8858_configs[] = {
+{
+ .name = "3264x2448_18fps",
+ .frm_fmt = {
+ .width = 3264,
+ .height = 2448,
+ .code = MEDIA_BUS_FMT_SBGGR10_1X10
+ },
+ .frm_intrvl = {
+ .interval = {
+ .numerator = 1,
+ .denominator = 18
+ }
+ },
+ .auto_exp_enabled = false,
+ .auto_gain_enabled = false,
+ .auto_wb_enabled = false,
+ .reg_table = (void *)ov8858_init_tab_3264_2448_18fps,
+ .reg_table_num_entries =
+ sizeof(ov8858_init_tab_3264_2448_18fps) /
+ sizeof(ov8858_init_tab_3264_2448_18fps[0]),
+ .reg_diff_table = NULL,
+ .reg_diff_table_num_entries = 0,
+ .v_blanking_time_us = 7251,
+ PLTFRM_CAM_ITF_MIPI_CFG(0, 4, 481, 24000000)
+ }
+};
+
+static struct ov_camera_module_config ov8858_configs_R1A[] = {
+ {
+ .name = "1632x1224_30fps",
+ .frm_fmt = {
+ .width = 1632,
+ .height = 1224,
+ .code = MEDIA_BUS_FMT_SBGGR10_1X10
+ },
+ .frm_intrvl = {
+ .interval = {
+ .numerator = 1,
+ .denominator = 30
+ }
+ },
+ .auto_exp_enabled = false,
+ .auto_gain_enabled = false,
+ .auto_wb_enabled = false,
+ .reg_table = (void *)ov8858_init_tab_1632_1224_30fps_R1A,
+ .reg_table_num_entries =
+ sizeof(ov8858_init_tab_1632_1224_30fps_R1A) /
+ sizeof(ov8858_init_tab_1632_1224_30fps_R1A[0]),
+ .v_blanking_time_us = 6579,
+ PLTFRM_CAM_ITF_MIPI_CFG(0, 2, 720, 24000000)
+ },
+ {
+ .name = "3264x2448_15fps",
+ .frm_fmt = {
+ .width = 3264,
+ .height = 2448,
+ .code = MEDIA_BUS_FMT_SBGGR10_1X10
+ },
+ .frm_intrvl = {
+ .interval = {
+ .numerator = 1,
+ .denominator = 15
+ }
+ },
+ .auto_exp_enabled = false,
+ .auto_gain_enabled = false,
+ .auto_wb_enabled = false,
+ .reg_table = (void *)ov8858_init_tab_3264_2448_15fps_R1A,
+ .reg_table_num_entries =
+ sizeof(ov8858_init_tab_3264_2448_15fps_R1A) /
+ sizeof(ov8858_init_tab_3264_2448_15fps_R1A[0]),
+ .v_blanking_time_us = 6579,
+ PLTFRM_CAM_ITF_MIPI_CFG(0, 2, 720, 24000000)
+ }
+};
+
+/*--------------------------------------------------------------------------*/
+
+static int ov8858_g_VTS(struct ov_camera_module *cam_mod, u32 *vts)
+{
+ u32 msb, lsb;
+ int ret;
+
+ ret = ov_camera_module_read_reg_table(
+ cam_mod,
+ ov8858_TIMING_VTS_HIGH_REG,
+ &msb);
+ if (IS_ERR_VALUE(ret))
+ goto err;
+
+ ret = ov_camera_module_read_reg_table(
+ cam_mod,
+ ov8858_TIMING_VTS_LOW_REG,
+ &lsb);
+ if (IS_ERR_VALUE(ret))
+ goto err;
+
+ *vts = (msb << 8) | lsb;
+ cam_mod->vts_cur = *vts;
+
+ return 0;
+err:
+ ov_camera_module_pr_err(cam_mod,
+ "failed with error (%d)\n", ret);
+ return ret;
+}
+
+/*--------------------------------------------------------------------------*/
+
+static int ov8858_auto_adjust_fps(struct ov_camera_module *cam_mod,
+ u32 exp_time)
+{
+ int ret;
+ u32 vts;
+
+ if ((cam_mod->exp_config.exp_time + ov8858_COARSE_INTG_TIME_MAX_MARGIN)
+ > cam_mod->vts_min)
+ vts = cam_mod->exp_config.exp_time +
+ ov8858_COARSE_INTG_TIME_MAX_MARGIN;
+ else
+ vts = cam_mod->vts_min;
+ ret = ov_camera_module_write_reg(cam_mod,
+ ov8858_TIMING_VTS_LOW_REG,
+ vts & 0xFF);
+ ret |= ov_camera_module_write_reg(cam_mod,
+ ov8858_TIMING_VTS_HIGH_REG,
+ (vts >> 8) & 0xFF);
+
+ if (IS_ERR_VALUE(ret)) {
+ ov_camera_module_pr_err(cam_mod,
+ "failed with error (%d)\n", ret);
+ } else {
+ ov_camera_module_pr_debug(cam_mod,
+ "updated vts = %d,vts_min=%d\n", vts, cam_mod->vts_min);
+ cam_mod->vts_cur = vts;
+ }
+
+ return ret;
+}
+
+/*--------------------------------------------------------------------------*/
+static int ov8858_write_aec(struct ov_camera_module *cam_mod)
+{
+ int ret = 0;
+
+ ov_camera_module_pr_debug(cam_mod,
+ "exp_time = %d, gain = %d, flash_mode = %d\n",
+ cam_mod->exp_config.exp_time,
+ cam_mod->exp_config.gain,
+ cam_mod->exp_config.flash_mode);
+
+ /*
+ * if the sensor is already streaming, write to shadow registers,
+ * if the sensor is in SW standby, write to active registers,
+ * if the sensor is off/registers are not writeable, do nothing
+ */
+ if ((cam_mod->state == OV_CAMERA_MODULE_SW_STANDBY) ||
+ (cam_mod->state == OV_CAMERA_MODULE_STREAMING)) {
+ u32 a_gain = cam_mod->exp_config.gain;
+ u32 exp_time;
+
+ a_gain = a_gain > 0x7ff ? 0x7ff : a_gain;
+ a_gain = a_gain * cam_mod->exp_config.gain_percent / 100;
+ exp_time = cam_mod->exp_config.exp_time << 4;
+ if (cam_mod->state == OV_CAMERA_MODULE_STREAMING)
+ ret = ov_camera_module_write_reg(cam_mod,
+ ov8858_AEC_GROUP_UPDATE_ADDRESS,
+ ov8858_AEC_GROUP_UPDATE_START_DATA);
+ if (!IS_ERR_VALUE(ret) && cam_mod->auto_adjust_fps)
+ ret = ov8858_auto_adjust_fps(cam_mod,
+ cam_mod->exp_config.exp_time);
+ ret |= ov_camera_module_write_reg(cam_mod,
+ ov8858_AEC_PK_LONG_GAIN_HIGH_REG,
+ ov8858_FETCH_MSB_GAIN(a_gain));
+ ret |= ov_camera_module_write_reg(cam_mod,
+ ov8858_AEC_PK_LONG_GAIN_LOW_REG,
+ ov8858_FETCH_LSB_GAIN(a_gain));
+ ret = ov_camera_module_write_reg(cam_mod,
+ ov8858_AEC_PK_LONG_EXPO_3RD_REG,
+ ov8858_FETCH_3RD_BYTE_EXP(exp_time));
+ ret |= ov_camera_module_write_reg(cam_mod,
+ ov8858_AEC_PK_LONG_EXPO_2ND_REG,
+ ov8858_FETCH_2ND_BYTE_EXP(exp_time));
+ ret |= ov_camera_module_write_reg(cam_mod,
+ ov8858_AEC_PK_LONG_EXPO_1ST_REG,
+ ov8858_FETCH_1ST_BYTE_EXP(exp_time));
+ if (cam_mod->state == OV_CAMERA_MODULE_STREAMING) {
+ ret = ov_camera_module_write_reg(cam_mod,
+ ov8858_AEC_GROUP_UPDATE_ADDRESS,
+ ov8858_AEC_GROUP_UPDATE_END_DATA);
+ ret = ov_camera_module_write_reg(cam_mod,
+ ov8858_AEC_GROUP_UPDATE_ADDRESS,
+ ov8858_AEC_GROUP_UPDATE_END_LAUNCH);
+ }
+ }
+
+ if (IS_ERR_VALUE(ret))
+ ov_camera_module_pr_err(cam_mod,
+ "failed with error (%d)\n", ret);
+ return ret;
+}
+
+/*--------------------------------------------------------------------------*/
+
+static int ov8858_g_ctrl(struct ov_camera_module *cam_mod, u32 ctrl_id)
+{
+ int ret = 0;
+
+ ov_camera_module_pr_debug(cam_mod, "\n");
+
+ switch (ctrl_id) {
+ case V4L2_CID_GAIN:
+ case V4L2_CID_EXPOSURE:
+ case V4L2_CID_FLASH_LED_MODE:
+ /* nothing to be done here */
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ if (IS_ERR_VALUE(ret))
+ ov_camera_module_pr_debug(cam_mod,
+ "failed with error (%d)\n", ret);
+ return ret;
+}
+
+/*--------------------------------------------------------------------------*/
+static int ov8858_filltimings(struct ov_camera_module_custom_config *custom)
+{
+ int i, j;
+ struct ov_camera_module_config *config;
+ struct ov_camera_module_timings *timings;
+ struct ov_camera_module_reg *reg_table;
+ int reg_table_num_entries;
+
+ for (i = 0; i < custom->num_configs; i++) {
+ config = &custom->configs[i];
+ reg_table = config->reg_table;
+ reg_table_num_entries = config->reg_table_num_entries;
+ timings = &config->timings;
+
+ memset(timings, 0x00, sizeof(*timings));
+ for (j = 0; j < reg_table_num_entries; j++) {
+ switch (reg_table[j].reg) {
+ case ov8858_TIMING_VTS_HIGH_REG:
+ timings->frame_length_lines =
+ ((reg_table[j].val << 8) |
+ (timings->frame_length_lines & 0xff));
+ break;
+ case ov8858_TIMING_VTS_LOW_REG:
+ timings->frame_length_lines =
+ (reg_table[j].val |
+ (timings->frame_length_lines & 0xff00));
+ break;
+ case ov8858_TIMING_HTS_HIGH_REG:
+ timings->line_length_pck =
+ ((reg_table[j].val << 8) |
+ timings->line_length_pck);
+ break;
+ case ov8858_TIMING_HTS_LOW_REG:
+ timings->line_length_pck =
+ (reg_table[j].val |
+ (timings->line_length_pck & 0xff00));
+ break;
+ case ov8858_TIMING_X_INC:
+ timings->binning_factor_x =
+ ((reg_table[j].val >> 4) + 1) / 2;
+ if (timings->binning_factor_x == 0)
+ timings->binning_factor_x = 1;
+ break;
+ case ov8858_TIMING_Y_INC:
+ timings->binning_factor_y =
+ ((reg_table[j].val >> 4) + 1) / 2;
+ if (timings->binning_factor_y == 0)
+ timings->binning_factor_y = 1;
+ break;
+ case ov8858_HORIZONTAL_START_HIGH_REG:
+ timings->crop_horizontal_start =
+ ((reg_table[j].val << 8) |
+ (timings->crop_horizontal_start &
+ 0xff));
+ break;
+ case ov8858_HORIZONTAL_START_LOW_REG:
+ timings->crop_horizontal_start =
+ (reg_table[j].val |
+ (timings->crop_horizontal_start &
+ 0xff00));
+ break;
+ case ov8858_VERTICAL_START_HIGH_REG:
+ timings->crop_vertical_start =
+ ((reg_table[j].val << 8) |
+ (timings->crop_vertical_start & 0xff));
+ break;
+ case ov8858_VERTICAL_START_LOW_REG:
+ timings->crop_vertical_start =
+ ((reg_table[j].val) |
+ (timings->crop_vertical_start &
+ 0xff00));
+ break;
+ case ov8858_HORIZONTAL_END_HIGH_REG:
+ timings->crop_horizontal_end =
+ ((reg_table[j].val << 8) |
+ (timings->crop_horizontal_end & 0xff));
+ break;
+ case ov8858_HORIZONTAL_END_LOW_REG:
+ timings->crop_horizontal_end =
+ (reg_table[j].val |
+ (timings->crop_horizontal_end &
+ 0xff00));
+ break;
+ case ov8858_VERTICAL_END_HIGH_REG:
+ timings->crop_vertical_end =
+ ((reg_table[j].val << 8) |
+ (timings->crop_vertical_end & 0xff));
+ break;
+ case ov8858_VERTICAL_END_LOW_REG:
+ timings->crop_vertical_end =
+ (reg_table[j].val |
+ (timings->crop_vertical_end & 0xff00));
+ break;
+ case ov8858_HORIZONTAL_OUTPUT_SIZE_HIGH_REG:
+ timings->sensor_output_width =
+ ((reg_table[j].val << 8) |
+ (timings->sensor_output_width & 0xff));
+ break;
+ case ov8858_HORIZONTAL_OUTPUT_SIZE_LOW_REG:
+ timings->sensor_output_width =
+ (reg_table[j].val |
+ (timings->sensor_output_width &
+ 0xff00));
+ break;
+ case ov8858_VERTICAL_OUTPUT_SIZE_HIGH_REG:
+ timings->sensor_output_height =
+ ((reg_table[j].val << 8) |
+ (timings->sensor_output_height & 0xff));
+ break;
+ case ov8858_VERTICAL_OUTPUT_SIZE_LOW_REG:
+ timings->sensor_output_height =
+ (reg_table[j].val |
+ (timings->sensor_output_height &
+ 0xff00));
+ break;
+ case ov8858_AEC_PK_LONG_EXPO_1ST_REG:
+ timings->exp_time =
+ ((reg_table[j].val) |
+ (timings->exp_time & 0xffff00));
+ break;
+ case ov8858_AEC_PK_LONG_EXPO_2ND_REG:
+ timings->exp_time =
+ ((reg_table[j].val << 8) |
+ (timings->exp_time & 0x00ff00));
+ break;
+ case ov8858_AEC_PK_LONG_EXPO_3RD_REG:
+ timings->exp_time =
+ (((reg_table[j].val & 0x0f) << 16) |
+ (timings->exp_time & 0xff0000));
+ break;
+ case ov8858_AEC_PK_LONG_GAIN_LOW_REG:
+ timings->gain =
+ (reg_table[j].val |
+ (timings->gain & 0x0700));
+ break;
+ case ov8858_AEC_PK_LONG_GAIN_HIGH_REG:
+ timings->gain =
+ (((reg_table[j].val & 0x07) << 8) |
+ (timings->gain & 0xff));
+ break;
+ }
+ }
+
+ timings->exp_time >>= 4;
+ timings->vt_pix_clk_freq_hz =
+ config->frm_intrvl.interval.denominator
+ * timings->frame_length_lines
+ * timings->line_length_pck;
+
+ timings->coarse_integration_time_min =
+ ov8858_COARSE_INTG_TIME_MIN;
+ timings->coarse_integration_time_max_margin =
+ ov8858_COARSE_INTG_TIME_MAX_MARGIN;
+
+ /* OV Sensor do not use fine integration time. */
+ timings->fine_integration_time_min =
+ ov8858_FINE_INTG_TIME_MIN;
+ timings->fine_integration_time_max_margin =
+ ov8858_FINE_INTG_TIME_MAX_MARGIN;
+ }
+
+ return 0;
+}
+
+static int ov8858_g_timings(struct ov_camera_module *cam_mod,
+ struct ov_camera_module_timings *timings)
+{
+ int ret = 0;
+ unsigned int vts;
+
+ if (IS_ERR_OR_NULL(cam_mod->active_config))
+ goto err;
+
+ *timings = cam_mod->active_config->timings;
+
+ vts = (!cam_mod->vts_cur) ?
+ timings->frame_length_lines :
+ cam_mod->vts_cur;
+ if (cam_mod->frm_intrvl_valid)
+ timings->vt_pix_clk_freq_hz =
+ cam_mod->frm_intrvl.interval.denominator *
+ vts * timings->line_length_pck;
+ else
+ timings->vt_pix_clk_freq_hz =
+ cam_mod->active_config->frm_intrvl.interval.denominator *
+ vts * timings->line_length_pck;
+
+ return ret;
+err:
+ ov_camera_module_pr_err(cam_mod,
+ "failed with error (%d)\n", ret);
+ return ret;
+}
+
+/*--------------------------------------------------------------------------*/
+
+static int ov8858_s_ctrl(struct ov_camera_module *cam_mod, u32 ctrl_id)
+{
+ int ret = 0;
+
+ ov_camera_module_pr_debug(cam_mod, "\n");
+
+ switch (ctrl_id) {
+ case V4L2_CID_GAIN:
+ case V4L2_CID_EXPOSURE:
+ ret = ov8858_write_aec(cam_mod);
+ break;
+ case V4L2_CID_FLASH_LED_MODE:
+ /* nothing to be done here */
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ if (IS_ERR_VALUE(ret))
+ ov_camera_module_pr_debug(cam_mod,
+ "failed with error (%d) 0x%x\n", ret, ctrl_id);
+ return ret;
+}
+
+/*--------------------------------------------------------------------------*/
+
+static int ov8858_s_ext_ctrls(struct ov_camera_module *cam_mod,
+ struct ov_camera_module_ext_ctrls *ctrls)
+{
+ int ret = 0;
+
+ /* Handles only exposure and gain together special case. */
+ if (ctrls->count == 1)
+ ret = ov8858_s_ctrl(cam_mod, ctrls->ctrls[0].id);
+ else if ((ctrls->count == 3) &&
+ ((ctrls->ctrls[0].id == V4L2_CID_GAIN &&
+ ctrls->ctrls[1].id == V4L2_CID_EXPOSURE) ||
+ (ctrls->ctrls[1].id == V4L2_CID_GAIN &&
+ ctrls->ctrls[0].id == V4L2_CID_EXPOSURE)))
+ ret = ov8858_write_aec(cam_mod);
+ else
+ ret = -EINVAL;
+
+ if (IS_ERR_VALUE(ret))
+ ov_camera_module_pr_debug(cam_mod,
+ "failed with error (%d)\n", ret);
+ return ret;
+}
+
+/*--------------------------------------------------------------------------*/
+int update_awb_gain(struct ov_camera_module *cam_mod)
+{
+ int R_gain = otp_ptr->R_gain;
+ int G_gain = otp_ptr->G_gain;
+ int B_gain = otp_ptr->B_gain;
+ int ret = 0;
+
+ if (R_gain > 0x400) {
+ ret |= ov_camera_module_write_reg(cam_mod, 0x5032,
+ R_gain >> 8);
+ ret |= ov_camera_module_write_reg(cam_mod, 0x5033,
+ R_gain & 0x00ff);
+ }
+ if (G_gain > 0x400) {
+ ret |= ov_camera_module_write_reg(cam_mod, 0x5034,
+ G_gain >> 8);
+ ret |= ov_camera_module_write_reg(cam_mod, 0x5035,
+ G_gain & 0x00ff);
+ }
+ if (B_gain > 0x400) {
+ ret |= ov_camera_module_write_reg(cam_mod, 0x5036,
+ B_gain >> 8);
+ ret |= ov_camera_module_write_reg(cam_mod, 0x5037,
+ B_gain & 0x00ff);
+ }
+
+ if (IS_ERR_VALUE(ret))
+ ov_camera_module_pr_err(cam_mod, "otp awb gain apply failed\n");
+ else
+ ov_camera_module_pr_debug(cam_mod,
+ "ov8858_update:%s, rgain:%x ggain %x bgain %x\n",
+ __func__, R_gain, G_gain, B_gain);
+
+ return ret;
+}
+
+int update_lenc(struct ov_camera_module *cam_mod)
+{
+ int i, temp = 0, ret = 0;
+
+ ret |= ov_camera_module_read_reg(cam_mod, 1, 0x5000, &temp);
+ temp = 0x80 | temp;
+ ret |= ov_camera_module_write_reg(cam_mod, 0x5000, temp);
+
+ if (IS_ERR_VALUE(ret)) {
+ ov_camera_module_pr_err(cam_mod,
+ "otp lenc apply failed at beginning\n");
+ return ret;
+ }
+
+ for (i = 0; i < 240; i++) {
+ ret |= ov_camera_module_write_reg(cam_mod, (0x5800 + i),
+ otp_ptr->lenc[i]);
+ if (IS_ERR_VALUE(ret)) {
+ ov_camera_module_pr_err(cam_mod,
+ "otp lenc apply failed during procesing\n");
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int ov8858_start_streaming(struct ov_camera_module *cam_mod)
+{
+ int ret = 0;
+
+ ov_camera_module_pr_debug(cam_mod,
+ "active config=%s\n", cam_mod->active_config->name);
+
+ if (otp_ptr && otp_ptr->otp_en == 1 &&
+ cam_mod->update_config &&
+ cam_mod->active_config->soft_reset) {
+ ov_camera_module_pr_debug(cam_mod,
+ "apply otp data for R2A module...\n");
+ update_awb_gain(cam_mod);
+ update_lenc(cam_mod);
+ }
+ ret = ov8858_g_VTS(cam_mod, &cam_mod->vts_min);
+ if (IS_ERR_VALUE(ret))
+ goto err;
+
+ if (IS_ERR_VALUE(ov_camera_module_write_reg(cam_mod, 0x0100, 1)))
+ goto err;
+
+ msleep(25);
+
+ return 0;
+err:
+ ov_camera_module_pr_err(cam_mod, "failed with error (%d)\n",
+ ret);
+ return ret;
+}
+
+/*--------------------------------------------------------------------------*/
+
+static int ov8858_stop_streaming(struct ov_camera_module *cam_mod)
+{
+ int ret = 0;
+
+ ov_camera_module_pr_debug(cam_mod, "\n");
+
+ ret = ov_camera_module_write_reg(cam_mod, 0x0100, 0);
+ if (IS_ERR_VALUE(ret))
+ goto err;
+
+ msleep(25);
+
+ return 0;
+err:
+ ov_camera_module_pr_err(cam_mod, "failed with error (%d)\n", ret);
+ return ret;
+}
+
+/*--------------------------------------------------------------------------*/
+/*
+ * call this function after ov8858 initialization
+ * return value: 0 update success
+ * 1, no OTP
+ */
+int __ov8858_read_otp_wb(struct ov_camera_module *cam_mod)
+{
+ int otp_flag = 0;
+ int addr = 0;
+ int ret = 0;
+ int temp1 = 0, temp2 = 0;
+
+ ret = ov_camera_module_read_reg(cam_mod, 1, 0x7010, &otp_flag);
+ if (IS_ERR_VALUE(ret)) {
+ ov_camera_module_pr_err(cam_mod,
+ "otp wb flag read failed\n");
+ return ret;
+ }
+ ov_camera_module_pr_debug(cam_mod, "otp wb flag is %0x\n", otp_flag);
+
+ if ((otp_flag & 0xc0) == 0x40)
+ addr = 0x7011; /* set addr to group 1 base */
+ else if ((otp_flag & 0x30) == 0x10)
+ addr = 0x7019; /* set addr to group 2 base */
+
+ if (addr != 0) {
+ ov_camera_module_pr_debug(cam_mod,
+ "otp wb addr is %0x\n", addr);
+ otp_ptr->flag = 0xc0;
+ ret |= ov_camera_module_read_reg(cam_mod, 1, addr,
+ &otp_ptr->module_integrator_id);
+ ret |= ov_camera_module_read_reg(cam_mod, 1, (addr + 1),
+ &otp_ptr->lens_id);
+ ret |= ov_camera_module_read_reg(cam_mod, 1, (addr + 2),
+ &otp_ptr->production_year);
+ ret |= ov_camera_module_read_reg(cam_mod, 1, (addr + 3),
+ &otp_ptr->production_month);
+ ret |= ov_camera_module_read_reg(cam_mod, 1, (addr + 4),
+ &otp_ptr->production_day);
+ ret |= ov_camera_module_read_reg(cam_mod, 1,
+ (addr + 5), &temp1);
+ ret |= ov_camera_module_read_reg(cam_mod, 1,
+ (addr + 7), &temp2);
+ otp_ptr->rg_ratio = (temp1 << 2) + (temp2 >> 6 & 0x03);
+ ret |= ov_camera_module_read_reg(cam_mod, 1,
+ (addr + 6), &temp1);
+ otp_ptr->bg_ratio = (temp1 << 2) + (temp2 >> 4 & 0x03);
+
+ if (IS_ERR_VALUE(ret)) {
+ ov_camera_module_pr_err(cam_mod,
+ "otp wb data read failed\n");
+ return 1;
+ }
+
+ } else {
+ ov_camera_module_pr_debug(cam_mod,
+ "no valid module info and awb data in otp\n");
+ otp_ptr->flag = 0;
+ otp_ptr->module_integrator_id = 0;
+ otp_ptr->lens_id = 0;
+ otp_ptr->production_year = 0;
+ otp_ptr->production_month = 0;
+ otp_ptr->production_day = 0;
+ otp_ptr->rg_ratio = 0;
+ otp_ptr->bg_ratio = 0;
+ return 1;
+ }
+
+ otp_ptr->R_gain = (RG_RATIO_TYPICAL * 1000) / otp_ptr->rg_ratio;
+ otp_ptr->B_gain = (BG_RATIO_TYPICAL * 1000) / otp_ptr->bg_ratio;
+ otp_ptr->G_gain = 1000;
+
+ if (otp_ptr->R_gain < 1000 || otp_ptr->B_gain < 1000) {
+ if (otp_ptr->R_gain < otp_ptr->B_gain)
+ temp1 = otp_ptr->R_gain;
+ else
+ temp1 = otp_ptr->B_gain;
+ } else {
+ temp1 = otp_ptr->G_gain;
+ }
+
+ otp_ptr->R_gain = 0x400 * otp_ptr->R_gain / temp1;
+ otp_ptr->B_gain = 0x400 * otp_ptr->B_gain / temp1;
+ otp_ptr->G_gain = 0x400 * otp_ptr->G_gain / temp1;
+
+ return ret;
+}
+
+int __ov8858_read_otp_vcm(struct ov_camera_module *cam_mod)
+{
+ int otp_flag = 0;
+ int addr = 0;
+ int ret = 0;
+ int temp1 = 0, temp2 = 0;
+
+ ret = ov_camera_module_read_reg(cam_mod, 1, 0x7021, &otp_flag);
+ if (IS_ERR_VALUE(ret)) {
+ ov_camera_module_pr_err(cam_mod,
+ "otp vcm flag read failed\n");
+ return ret;
+ }
+ ov_camera_module_pr_debug(cam_mod, "otp vcm flag is %0x\n", otp_flag);
+
+ if ((otp_flag & 0xc0) == 0x40)
+ addr = 0x7022; /* set addr to group 1 base */
+ else if ((otp_flag & 0x30) == 0x10)
+ addr = 0x7025; /* set addr to group 2 base */
+
+ if (addr != 0) {
+ ov_camera_module_pr_debug(cam_mod,
+ "otp vcm addr is %0x\n", addr);
+ otp_ptr->flag |= 0x20;
+ ret |= ov_camera_module_read_reg(cam_mod, 1, addr, &temp1);
+ ret |= ov_camera_module_read_reg(cam_mod, 1,
+ (addr + 2), &temp2);
+ otp_ptr->VCM_start = (temp1 << 2) | (temp1 >> 6 & 0x03);
+ ret |= ov_camera_module_read_reg(cam_mod, 1,
+ (addr + 1), &temp1);
+ otp_ptr->VCM_end = (temp1 << 2) + (temp2 >> 4 & 0x03);
+ otp_ptr->VCM_dir = (temp2 >> 2 & 0x03);
+
+ if (IS_ERR_VALUE(ret))
+ ov_camera_module_pr_err(cam_mod,
+ "otp vcm read fail!\n");
+ } else {
+ ov_camera_module_pr_debug(cam_mod,
+ "no valid vcm data in otp\n");
+ otp_ptr->VCM_end = 0;
+ otp_ptr->VCM_end = 0;
+ otp_ptr->VCM_dir = 0;
+ return 1;
+ }
+
+ return ret;
+}
+
+int __ov8858_read_otp_lenc(struct ov_camera_module *cam_mod)
+{
+ int otp_flag = 0;
+ int addr = 0;
+ int ret = 0, i = 0;
+ int checksum = 0;
+
+ ret = ov_camera_module_read_reg(cam_mod, 1, 0x7028, &otp_flag);
+ if (IS_ERR_VALUE(ret)) {
+ ov_camera_module_pr_err(cam_mod,
+ "otp lenc flag read failed\n");
+ return ret;
+ }
+
+ ov_camera_module_pr_debug(cam_mod,
+ "otp lenc flag is 0x%0x\n", otp_flag);
+
+ if ((otp_flag & 0xc0) == 0x40)
+ addr = 0x7029; /* set addr to group 1 base */
+ else if ((otp_flag & 0x30) == 0x10)
+ addr = 0x711a; /* set addr to group 2 base */
+
+ if (addr != 0) {
+ for (i = 0; i < 240; i++) {
+ ret |= ov_camera_module_read_reg(cam_mod, 1, (addr + i),
+ &otp_ptr->lenc[i]);
+ if (IS_ERR_VALUE(ret)) {
+ ov_camera_module_pr_err(cam_mod,
+ "otp lenc data read failed\n");
+ return ret;
+ }
+ checksum += otp_ptr->lenc[i];
+ }
+
+ checksum = (checksum) % 255 + 1;
+ ret |= ov_camera_module_read_reg(cam_mod, 1, (addr + 240),
+ &otp_ptr->checksum);
+ if (IS_ERR_VALUE(ret)) {
+ ov_camera_module_pr_err(cam_mod,
+ "otp lenc checksum read failed\n");
+ return ret;
+ }
+
+ if (otp_ptr->checksum == checksum) {
+ otp_ptr->flag |= 0x10;
+ } else {
+ ov_camera_module_pr_err(cam_mod,
+ "otp lenc checksum no match!\n");
+ return 1;
+ }
+ } else {
+ for (i = 0; i < 240; i++) {
+ ov_camera_module_pr_debug(cam_mod,
+ "no valid lenc data in otp\n");
+ otp_ptr->lenc[i] = 0;
+ }
+ return 1;
+ }
+
+ return ret;
+}
+
+static int ov8858_otp_read(struct ov_camera_module *cam_mod)
+{
+ int ret = 0;
+ int temp = 0;
+ int reg = 0;
+ int otp_ret = 0;
+ struct i2c_client *client = v4l2_get_subdevdata(&cam_mod->sd);
+
+ ov_camera_module_pr_debug(cam_mod, "\n");
+
+ if (otp_ptr) {
+ ov_camera_module_pr_debug(cam_mod, "OTP data loaded already\n");
+ return 0;
+ }
+
+ otp_ptr = kzalloc(sizeof(*otp_ptr), GFP_KERNEL);
+ if (!otp_ptr) {
+ ov_camera_module_pr_err(cam_mod, "otp alloc fail!\n");
+ return -ENOMEM;
+ }
+
+ ov_camera_module_write_reg(cam_mod, 0x0100, 1);
+
+ /* set 0x5002[3] to "0" before ops */
+ ret = ov_camera_module_read_reg(cam_mod, 1, 0x5002, &temp);
+ if (IS_ERR_VALUE(ret)) {
+ ov_camera_module_pr_err(cam_mod,
+ "otp read failed at phase1\n");
+ return ret;
+ }
+
+ ov_camera_module_pr_debug(cam_mod, "otp read phase1 pass\n");
+
+ ret |= ov_camera_module_write_reg(cam_mod, 0x5002,
+ ((temp & (~0x08))));
+
+ ret |= ov_camera_module_write_reg(cam_mod, 0x3d84, 0xc0);
+ /* otp start addr */
+ ret |= ov_camera_module_write_reg(cam_mod, 0x3d88, 0x70);
+ ret |= ov_camera_module_write_reg(cam_mod, 0x3d89, 0x10);
+ /* otp end addr */
+ ret |= ov_camera_module_write_reg(cam_mod, 0x3d8A, 0x72);
+ ret |= ov_camera_module_write_reg(cam_mod, 0x3d8B, 0x0a);
+ /* load otp into buffer */
+ ret |= ov_camera_module_write_reg(cam_mod, 0x3d81, 0x01);
+ if (IS_ERR_VALUE(ret)) {
+ ov_camera_module_pr_err(cam_mod,
+ "otp read failed at phase2\n");
+ return ret;
+ }
+
+ ov_camera_module_pr_debug(cam_mod, "otp read phase2 pass\n");
+
+ usleep_range(10000, 15000);
+
+ /* otp wb read */
+ otp_ret = __ov8858_read_otp_wb(cam_mod);
+
+ if (otp_ret)
+ ov_camera_module_pr_err(cam_mod, "fail to read OTP wb!\n");
+ else
+ ov_camera_module_pr_debug(cam_mod, "read otp wb success\n");
+
+ /* otp vcm read */
+ otp_ret = __ov8858_read_otp_vcm(cam_mod);
+
+ if (otp_ret)
+ ov_camera_module_pr_err(cam_mod, "fail to read OTP vcm!\n");
+ else
+ ov_camera_module_pr_debug(cam_mod, "read otp vcm success\n");
+
+ /* otp lenc read */
+ otp_ret = __ov8858_read_otp_lenc(cam_mod);
+
+ if (otp_ret) {
+ ov_camera_module_pr_err(cam_mod, "fail to read OTP lenc!\n");
+ goto readotperr;
+ } else {
+ ov_camera_module_pr_debug(cam_mod, "read otp lenc success\n");
+ }
+ /* clear data afer read */
+ for (reg = 0x7010; reg <= 0x720a; reg++) {
+ ret |= ov_camera_module_write_reg(cam_mod, reg, 0);
+ if (IS_ERR_VALUE(ret)) {
+ ov_camera_module_pr_err(cam_mod,
+ "otp clear data failed at phase3\n");
+ return ret;
+ }
+ }
+
+readotperr:
+ /* set 0x5002[3] to "1" after ops */
+ ret = ov_camera_module_read_reg(cam_mod, 1, 0x5002, &temp);
+ if (IS_ERR_VALUE(ret)) {
+ ov_camera_module_pr_err(cam_mod,
+ "otp exit failed at phase 4\n");
+ return ret;
+ }
+
+ ov_camera_module_pr_debug(cam_mod, "0x5002 is 0x%0x\n", temp);
+
+ ret |= ov_camera_module_write_reg(cam_mod, 0x5002,
+ (0x08 | (temp & (~0x08))));
+ ov_camera_module_write_reg(cam_mod, 0x0100, 0);
+ if (otp_ret) {
+ otp_ptr->otp_en = 0;
+ ov_camera_module_pr_err(
+ cam_mod,
+ "get otp data failed\n");
+ } else {
+ otp_ptr->otp_en = 1;
+ dev_info(&client->dev, "get otp data success\n");
+ }
+ return ret;
+}
+
+/*--------------------------------------------------------------------------*/
+
+static int ov8858_check_camera_id(struct ov_camera_module *cam_mod)
+{
+ u32 pidh, pidl, vid = 0;
+ int ret = 0;
+ struct i2c_client *client;
+
+ ov_camera_module_pr_debug(cam_mod, "\n");
+
+ ret |= ov_camera_module_read_reg(cam_mod, 1, ov8858_PIDH_ADDR, &pidh);
+ ret |= ov_camera_module_read_reg(cam_mod, 1, ov8858_PIDL_ADDR, &pidl);
+ if (IS_ERR_VALUE(ret)) {
+ ov_camera_module_pr_err(cam_mod,
+ "register read failed, camera module powered off?\n");
+ goto err;
+ }
+
+ if ((pidh == ov8858_PIDH_MAGIC) && (pidl == ov8858_PIDL_MAGIC))
+ ov_camera_module_pr_debug(cam_mod,
+ "successfully detected camera ID 0x%02x%02x\n",
+ pidh, pidl);
+ else {
+ ov_camera_module_pr_err(cam_mod,
+ "wrong camera ID, expected 0x%02x%02x, detected 0x%02x%02x\n",
+ ov8858_PIDH_MAGIC, ov8858_PIDL_MAGIC, pidh, pidl);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret |= ov_camera_module_read_reg(cam_mod, 1, 0x302a, &vid);
+ if (IS_ERR_VALUE(ret)) {
+ ov_camera_module_pr_err(cam_mod,
+ "register read failed, camera module powered off?\n");
+ goto err;
+ } else
+ ov_camera_module_pr_debug(cam_mod,
+ "ov8858 chip version is 0x%2x\n", vid);
+
+ client = v4l2_get_subdevdata(&cam_mod->sd);
+ if ((vid == 0xb1) || (vid == 0xb0)) {
+ ov8858_custom_config.configs = ov8858_configs_R1A;
+ ov8858_custom_config.num_configs =
+ sizeof(ov8858_configs_R1A)
+ / sizeof(ov8858_configs_R1A[0]);
+ dev_info(&client->dev, "init setting for r1a\n");
+ } else {
+ dev_info(&client->dev, "init setting for r2a\n");
+ }
+
+ ov8858_filltimings(&ov8858_custom_config);
+ cam_mod->custom = ov8858_custom_config;
+
+ ov_camera_module_pr_debug(cam_mod,
+ "ov8858 chip version is 0x%2x,module config no. is %d\n",
+ vid,
+ cam_mod->custom.num_configs);
+ return 0;
+err:
+ ov_camera_module_pr_err(cam_mod, "failed with error (%d)\n", ret);
+ return ret;
+}
+
+static int ov8858_g_exposure_valid_frame(struct ov_camera_module *cam_mod)
+{
+ return ov8858_EXP_VALID_FRAMES;
+}
+
+/* ======================================================================== */
+/* This part is platform dependent */
+/* ======================================================================== */
+
+static struct v4l2_subdev_core_ops ov8858_camera_module_core_ops = {
+ .g_ctrl = ov_camera_module_g_ctrl,
+ .s_ctrl = ov_camera_module_s_ctrl,
+ .s_ext_ctrls = ov_camera_module_s_ext_ctrls,
+ .s_power = ov_camera_module_s_power,
+ .ioctl = ov_camera_module_ioctl
+};
+
+static struct v4l2_subdev_video_ops ov8858_camera_module_video_ops = {
+ .s_frame_interval = ov_camera_module_s_frame_interval,
+ .s_stream = ov_camera_module_s_stream
+};
+
+static struct v4l2_subdev_pad_ops ov8858_camera_module_pad_ops = {
+ .enum_frame_interval = ov_camera_module_enum_frameintervals,
+ .get_fmt = ov_camera_module_g_fmt,
+ .set_fmt = ov_camera_module_s_fmt,
+};
+
+static struct v4l2_subdev_ops ov8858_camera_module_ops = {
+ .core = &ov8858_camera_module_core_ops,
+ .video = &ov8858_camera_module_video_ops,
+ .pad = &ov8858_camera_module_pad_ops
+};
+
+static struct ov_camera_module_custom_config ov8858_custom_config = {
+ .start_streaming = ov8858_start_streaming,
+ .stop_streaming = ov8858_stop_streaming,
+ .s_ctrl = ov8858_s_ctrl,
+ .s_ext_ctrls = ov8858_s_ext_ctrls,
+ .g_ctrl = ov8858_g_ctrl,
+ .g_timings = ov8858_g_timings,
+ .check_camera_id = ov8858_check_camera_id,
+ .g_exposure_valid_frame = ov8858_g_exposure_valid_frame,
+ .read_otp = ov8858_otp_read,
+ .configs = ov8858_configs,
+ .num_configs = ARRAY_SIZE(ov8858_configs),
+ .power_up_delays_ms = {5, 20, 0}
+};
+
+static int ov8858_probe(
+ struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ dev_info(&client->dev, "probing...\n");
+ ov8858_filltimings(&ov8858_custom_config);
+ v4l2_i2c_subdev_init(&ov8858.sd, client, &ov8858_camera_module_ops);
+ ov8858.custom = ov8858_custom_config;
+
+ dev_info(&client->dev, "probing successful\n");
+
+ return 0;
+}
+
+static int ov8858_remove(struct i2c_client *client)
+{
+ struct ov_camera_module *cam_mod = i2c_get_clientdata(client);
+
+ dev_info(&client->dev, "removing device...\n");
+
+ if (!client->adapter)
+ return -ENODEV; /* our client isn't attached */
+
+ ov_camera_module_release(cam_mod);
+
+ kfree(otp_ptr);
+ dev_info(&client->dev, "removed\n");
+ return 0;
+}
+
+static const struct i2c_device_id ov8858_id[] = {
+ { ov8858_DRIVER_NAME, 0 },
+ { }
+};
+
+static const struct of_device_id ov8858_of_match[] = {
+ {.compatible = "omnivision,ov8858-v4l2-i2c-subdev"},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, ov8858_id);
+
+static struct i2c_driver ov8858_i2c_driver = {
+ .driver = {
+ .name = ov8858_DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = ov8858_of_match
+ },
+ .probe = ov8858_probe,
+ .remove = ov8858_remove,
+ .id_table = ov8858_id,
+};
+
+module_i2c_driver(ov8858_i2c_driver);
+
+MODULE_DESCRIPTION("SoC Camera driver for ov8858");
+MODULE_AUTHOR("George");
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * ov_camera_module.c
+ *
+ * Generic omnivision sensor driver
+ *
+ * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd.
+ *
+ * Copyright (C) 2012-2014 Intel Mobile Communications GmbH
+ *
+ * Copyright (C) 2008 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+
+#include <linux/delay.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-device.h>
+#include <media/videobuf-core.h>
+#include <linux/slab.h>
+#include <linux/gcd.h>
+#include <media/v4l2-controls_rockchip.h>
+
+#include "ov_camera_module.h"
+
+static struct ov_camera_module *to_ov_camera_module(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct ov_camera_module, sd);
+}
+
+/* ======================================================================== */
+
+static void ov_camera_module_reset(
+ struct ov_camera_module *cam_mod)
+{
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "\n");
+
+ cam_mod->inited = false;
+ cam_mod->active_config = NULL;
+ cam_mod->update_config = true;
+ cam_mod->frm_fmt_valid = false;
+ cam_mod->frm_intrvl_valid = false;
+ cam_mod->exp_config.auto_exp = false;
+ cam_mod->exp_config.auto_gain = false;
+ cam_mod->wb_config.auto_wb = false;
+ cam_mod->hflip = false;
+ cam_mod->vflip = false;
+ cam_mod->auto_adjust_fps = true;
+ cam_mod->rotation = 0;
+ cam_mod->ctrl_updt = 0;
+ cam_mod->state = OV_CAMERA_MODULE_POWER_OFF;
+ cam_mod->state_before_suspend = OV_CAMERA_MODULE_POWER_OFF;
+
+ cam_mod->exp_config.exp_time = 0;
+ cam_mod->exp_config.gain = 0;
+ cam_mod->vts_cur = 0;
+}
+
+/* ======================================================================== */
+
+static void ov_camera_module_set_active_config(
+ struct ov_camera_module *cam_mod,
+ struct ov_camera_module_config *new_config)
+{
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "\n");
+
+ if (IS_ERR_OR_NULL(new_config)) {
+ cam_mod->active_config = new_config;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "no active config\n");
+ } else {
+ cam_mod->ctrl_updt &= OV_CAMERA_MODULE_CTRL_UPDT_AUTO_EXP |
+ OV_CAMERA_MODULE_CTRL_UPDT_AUTO_GAIN |
+ OV_CAMERA_MODULE_CTRL_UPDT_AUTO_WB;
+ if (new_config->auto_exp_enabled !=
+ cam_mod->exp_config.auto_exp) {
+ cam_mod->ctrl_updt |=
+ OV_CAMERA_MODULE_CTRL_UPDT_AUTO_EXP;
+ cam_mod->exp_config.auto_exp =
+ new_config->auto_exp_enabled;
+ }
+ if (new_config->auto_gain_enabled !=
+ cam_mod->exp_config.auto_gain) {
+ cam_mod->ctrl_updt |=
+ OV_CAMERA_MODULE_CTRL_UPDT_AUTO_GAIN;
+ cam_mod->exp_config.auto_gain =
+ new_config->auto_gain_enabled;
+ }
+ if (new_config->auto_wb_enabled !=
+ cam_mod->wb_config.auto_wb) {
+ cam_mod->ctrl_updt |=
+ OV_CAMERA_MODULE_CTRL_UPDT_AUTO_WB;
+ cam_mod->wb_config.auto_wb =
+ new_config->auto_wb_enabled;
+ }
+ if (new_config != cam_mod->active_config) {
+ cam_mod->update_config = true;
+ cam_mod->active_config = new_config;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "activating config '%s'\n",
+ cam_mod->active_config->name);
+ }
+ }
+}
+
+/* ======================================================================== */
+
+static struct ov_camera_module_config *ov_camera_module_find_config(
+ struct ov_camera_module *cam_mod,
+ struct v4l2_mbus_framefmt *fmt,
+ struct v4l2_subdev_frame_interval *frm_intrvl)
+{
+ u32 i;
+ unsigned long gcdiv;
+ struct v4l2_subdev_frame_interval norm_interval;
+
+ if (!IS_ERR_OR_NULL(fmt))
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "%dx%d, fmt code 0x%04x\n",
+ fmt->width, fmt->height, fmt->code);
+
+ if (!IS_ERR_OR_NULL(frm_intrvl))
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "frame interval %d/%d\n",
+ frm_intrvl->interval.numerator,
+ frm_intrvl->interval.denominator);
+
+ for (i = 0; i < cam_mod->custom.num_configs; i++) {
+ if (!IS_ERR_OR_NULL(frm_intrvl)) {
+ gcdiv = gcd(cam_mod->custom.configs[i].
+ frm_intrvl.interval.numerator,
+ cam_mod->custom.configs[i].
+ frm_intrvl.interval.denominator);
+ norm_interval.interval.numerator =
+ cam_mod->custom.configs[i].
+ frm_intrvl.interval.numerator / gcdiv;
+ norm_interval.interval.denominator =
+ cam_mod->custom.configs[i].
+ frm_intrvl.interval.denominator / gcdiv;
+ if ((frm_intrvl->interval.numerator !=
+ norm_interval.interval.numerator) ||
+ (frm_intrvl->interval.denominator !=
+ norm_interval.interval.denominator))
+ continue;
+ }
+ if (!IS_ERR_OR_NULL(fmt)) {
+ if ((cam_mod->custom.configs[i].frm_fmt.width !=
+ fmt->width) ||
+ (cam_mod->custom.configs[i].frm_fmt.height !=
+ fmt->height) ||
+ (cam_mod->custom.configs[i].frm_fmt.code !=
+ fmt->code)) {
+ continue;
+ }
+ }
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "found matching config %s\n",
+ cam_mod->custom.configs[i].name);
+ return &cam_mod->custom.configs[i];
+ }
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "no matching config found\n");
+
+ return ERR_PTR(-EINVAL);
+}
+
+/* ======================================================================== */
+
+static int ov_camera_module_write_config(
+ struct ov_camera_module *cam_mod)
+{
+ int ret = 0;
+ struct ov_camera_module_reg *reg_table;
+ u32 reg_table_num_entries;
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "\n");
+
+ if (IS_ERR_OR_NULL(cam_mod->active_config)) {
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "no active sensor configuration");
+ ret = -EFAULT;
+ goto err;
+ }
+
+ if (!cam_mod->inited) {
+ cam_mod->active_config->soft_reset = true;
+ reg_table = cam_mod->active_config->reg_table;
+ reg_table_num_entries =
+ cam_mod->active_config->reg_table_num_entries;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "write config %s\n",
+ cam_mod->active_config->name);
+ } else {
+ if (cam_mod->active_config->reg_diff_table &&
+ cam_mod->active_config->reg_diff_table_num_entries) {
+ cam_mod->active_config->soft_reset = false;
+ reg_table = cam_mod->active_config->reg_diff_table;
+ reg_table_num_entries =
+ cam_mod->active_config->reg_diff_table_num_entries;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "write config %s%s\n",
+ cam_mod->active_config->name, "_diff");
+ } else {
+ cam_mod->active_config->soft_reset = true;
+ reg_table = cam_mod->active_config->reg_table;
+ reg_table_num_entries =
+ cam_mod->active_config->reg_table_num_entries;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "write config %s\n",
+ cam_mod->active_config->name);
+ }
+ }
+
+ if (!IS_ERR_OR_NULL(cam_mod->custom.set_flip))
+ cam_mod->custom.set_flip(cam_mod,
+ reg_table, reg_table_num_entries);
+
+ ret = pltfrm_camera_module_write_reglist(&cam_mod->sd,
+ reg_table, reg_table_num_entries);
+ if (IS_ERR_VALUE(ret))
+ goto err;
+ ret = pltfrm_camera_module_patch_config(&cam_mod->sd,
+ &cam_mod->frm_fmt,
+ &cam_mod->frm_intrvl);
+ if (IS_ERR_VALUE(ret))
+ goto err;
+
+ return 0;
+err:
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "failed with error %d\n", ret);
+ return ret;
+}
+
+static int ov_camera_module_attach(
+ struct ov_camera_module *cam_mod)
+{
+ int ret = 0;
+ struct ov_camera_module_custom_config *custom;
+
+ custom = &cam_mod->custom;
+
+ if (custom->check_camera_id) {
+ ov_camera_module_s_power(&cam_mod->sd, 1);
+ ret = custom->check_camera_id(cam_mod);
+ ov_camera_module_s_power(&cam_mod->sd, 0);
+ if (ret != 0)
+ goto err;
+ }
+
+ return 0;
+err:
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "failed with error %d\n", ret);
+ ov_camera_module_release(cam_mod);
+ return ret;
+}
+
+/* ======================================================================== */
+
+int ov_camera_module_try_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *fmt)
+{
+ struct ov_camera_module *cam_mod = to_ov_camera_module(sd);
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "%dx%d, fmt code 0x%04x\n",
+ fmt->width, fmt->height, fmt->code);
+
+ if (IS_ERR_OR_NULL(ov_camera_module_find_config(cam_mod, fmt, NULL))) {
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "format not supported\n");
+ return -EINVAL;
+ }
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "format supported\n");
+
+ return 0;
+}
+
+/* ======================================================================== */
+
+int ov_camera_module_s_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format)
+{
+ struct ov_camera_module *cam_mod = to_ov_camera_module(sd);
+ struct v4l2_mbus_framefmt *fmt = &format->format;
+ int ret = 0;
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "%dx%d, fmt code 0x%04x\n",
+ fmt->width, fmt->height, fmt->code);
+
+ if (IS_ERR_OR_NULL(ov_camera_module_find_config(cam_mod, fmt, NULL))) {
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "format %dx%d, code 0x%04x, not supported\n",
+ fmt->width, fmt->height, fmt->code);
+ ret = -EINVAL;
+ goto err;
+ }
+ cam_mod->frm_fmt_valid = true;
+ cam_mod->frm_fmt = *fmt;
+ if (cam_mod->frm_intrvl_valid) {
+ ov_camera_module_set_active_config(cam_mod,
+ ov_camera_module_find_config(cam_mod,
+ fmt, &cam_mod->frm_intrvl));
+ }
+ return 0;
+err:
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "failed with error %d\n", ret);
+ return ret;
+}
+
+/* ======================================================================== */
+
+int ov_camera_module_g_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format)
+{
+ struct ov_camera_module *cam_mod = to_ov_camera_module(sd);
+ struct v4l2_mbus_framefmt *fmt = &format->format;
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "\n");
+
+ if (cam_mod->active_config) {
+ fmt->code = cam_mod->active_config->frm_fmt.code;
+ fmt->width = cam_mod->active_config->frm_fmt.width;
+ fmt->height = cam_mod->active_config->frm_fmt.height;
+ return 0;
+ }
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "no active config\n");
+
+ return -1;
+}
+
+/* ======================================================================== */
+
+int ov_camera_module_s_frame_interval(
+ struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *interval)
+{
+ struct ov_camera_module *cam_mod = to_ov_camera_module(sd);
+ unsigned long gcdiv;
+ struct v4l2_subdev_frame_interval norm_interval;
+ int ret = 0;
+
+ if ((interval->interval.denominator == 0) ||
+ (interval->interval.numerator == 0)) {
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "invalid frame interval %d/%d\n",
+ interval->interval.numerator,
+ interval->interval.denominator);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "%d/%d (%dfps)\n",
+ interval->interval.numerator, interval->interval.denominator,
+ (interval->interval.denominator +
+ (interval->interval.numerator >> 1)) /
+ interval->interval.numerator);
+
+ /* normalize interval */
+ gcdiv = gcd(interval->interval.numerator,
+ interval->interval.denominator);
+ norm_interval.interval.numerator =
+ interval->interval.numerator / gcdiv;
+ norm_interval.interval.denominator =
+ interval->interval.denominator / gcdiv;
+
+ if (IS_ERR_OR_NULL(ov_camera_module_find_config(cam_mod,
+ NULL, &norm_interval))) {
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "frame interval %d/%d not supported\n",
+ interval->interval.numerator,
+ interval->interval.denominator);
+ ret = -EINVAL;
+ goto err;
+ }
+ cam_mod->frm_intrvl_valid = true;
+ cam_mod->frm_intrvl = norm_interval;
+ if (cam_mod->frm_fmt_valid) {
+ ov_camera_module_set_active_config(cam_mod,
+ ov_camera_module_find_config(cam_mod,
+ &cam_mod->frm_fmt, interval));
+ }
+ return 0;
+err:
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "failed with error %d\n", ret);
+ return ret;
+}
+
+/* ======================================================================== */
+
+int ov_camera_module_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ int ret = 0;
+ struct ov_camera_module *cam_mod = to_ov_camera_module(sd);
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "%d\n", enable);
+
+ if (enable) {
+ if (cam_mod->state == OV_CAMERA_MODULE_STREAMING)
+ return 0;
+ if (IS_ERR_OR_NULL(cam_mod->active_config)) {
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "no active sensor configuration, cannot start streaming\n");
+ ret = -EFAULT;
+ goto err;
+ }
+ if (cam_mod->state != OV_CAMERA_MODULE_SW_STANDBY) {
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "sensor is not powered on (in state %d), cannot start streaming\n",
+ cam_mod->state);
+ ret = -EINVAL;
+ goto err;
+ }
+ if (cam_mod->update_config)
+ ret = ov_camera_module_write_config(cam_mod);
+ if (IS_ERR_VALUE(ret))
+ goto err;
+
+ ret = cam_mod->custom.start_streaming(cam_mod);
+ if (IS_ERR_VALUE(ret))
+ goto err;
+ if (!cam_mod->inited && cam_mod->update_config)
+ cam_mod->inited = true;
+ cam_mod->update_config = false;
+ cam_mod->ctrl_updt = 0;
+ mdelay(cam_mod->custom.power_up_delays_ms[2]);
+ cam_mod->state = OV_CAMERA_MODULE_STREAMING;
+ } else {
+ int pclk;
+ int wait_ms;
+ struct isp_supplemental_sensor_mode_data timings;
+
+ if (cam_mod->state != OV_CAMERA_MODULE_STREAMING)
+ return 0;
+ ret = cam_mod->custom.stop_streaming(cam_mod);
+ if (IS_ERR_VALUE(ret))
+ goto err;
+
+ ret = ov_camera_module_ioctl(sd,
+ RK_VIDIOC_SENSOR_MODE_DATA,
+ &timings);
+
+ cam_mod->state = OV_CAMERA_MODULE_SW_STANDBY;
+
+ if (IS_ERR_VALUE(ret))
+ goto err;
+
+ pclk = timings.vt_pix_clk_freq_hz / 1000;
+
+ if (!pclk)
+ goto err;
+
+ wait_ms =
+ (timings.line_length_pck *
+ timings.frame_length_lines) /
+ pclk;
+
+ /*
+ * wait for a frame period to make sure that there is
+ * no pending frame left.
+ */
+
+ msleep(wait_ms + 1);
+ }
+
+ cam_mod->state_before_suspend = cam_mod->state;
+
+ return 0;
+err:
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "failed with error %d\n", ret);
+ return ret;
+}
+
+/* ======================================================================== */
+
+int ov_camera_module_s_power(struct v4l2_subdev *sd, int on)
+{
+ int ret = 0;
+ struct ov_camera_module *cam_mod = to_ov_camera_module(sd);
+ struct v4l2_subdev *af_ctrl;
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "%d\n", on);
+
+ if (on) {
+ if (cam_mod->state == OV_CAMERA_MODULE_POWER_OFF) {
+ ret = pltfrm_camera_module_s_power(&cam_mod->sd, 1);
+ if (!IS_ERR_VALUE(ret)) {
+ mdelay(cam_mod->custom.power_up_delays_ms[0]);
+ cam_mod->state = OV_CAMERA_MODULE_HW_STANDBY;
+ }
+ }
+ if (cam_mod->state == OV_CAMERA_MODULE_HW_STANDBY) {
+ ret = pltfrm_camera_module_set_pin_state(&cam_mod->sd,
+ PLTFRM_CAMERA_MODULE_PIN_PD,
+ PLTFRM_CAMERA_MODULE_PIN_STATE_INACTIVE);
+ if (!IS_ERR_VALUE(ret)) {
+ mdelay(cam_mod->custom.power_up_delays_ms[1]);
+ cam_mod->state = OV_CAMERA_MODULE_SW_STANDBY;
+ if (!IS_ERR_OR_NULL(
+ cam_mod->custom.init_common) &&
+ cam_mod->custom.init_common(
+ cam_mod))
+ usleep_range(1000, 1500);
+
+ af_ctrl = pltfrm_camera_module_get_af_ctrl(sd);
+ if (!IS_ERR_OR_NULL(af_ctrl)) {
+ v4l2_subdev_call(af_ctrl,
+ core, init, 0);
+ }
+ }
+ }
+ if (cam_mod->update_config) {
+ ov_camera_module_write_config(cam_mod);
+ cam_mod->update_config = false;
+ }
+ } else {
+ if (cam_mod->state == OV_CAMERA_MODULE_STREAMING) {
+ ret = ov_camera_module_s_stream(sd, 0);
+ if (!IS_ERR_VALUE(ret))
+ cam_mod->state = OV_CAMERA_MODULE_SW_STANDBY;
+ }
+ if (cam_mod->state == OV_CAMERA_MODULE_SW_STANDBY) {
+ ret = pltfrm_camera_module_set_pin_state(
+ &cam_mod->sd,
+ PLTFRM_CAMERA_MODULE_PIN_PD,
+ PLTFRM_CAMERA_MODULE_PIN_STATE_ACTIVE);
+
+ if (!IS_ERR_VALUE(ret))
+ cam_mod->state = OV_CAMERA_MODULE_HW_STANDBY;
+ }
+ if (cam_mod->state == OV_CAMERA_MODULE_HW_STANDBY) {
+ ret = pltfrm_camera_module_s_power(&cam_mod->sd, 0);
+ if (!IS_ERR_VALUE(ret)) {
+ cam_mod->state = OV_CAMERA_MODULE_POWER_OFF;
+ ov_camera_module_reset(cam_mod);
+ }
+ }
+ }
+
+ cam_mod->state_before_suspend = cam_mod->state;
+
+ if (IS_ERR_VALUE(ret)) {
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "%s failed, camera left in state %d\n",
+ on ? "on" : "off", cam_mod->state);
+ goto err;
+ } else
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "camera powered %s\n", on ? "on" : "off");
+
+ return 0;
+err:
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "failed with error %d\n", ret);
+ return ret;
+}
+
+/* ======================================================================== */
+
+int ov_camera_module_g_ctrl(struct v4l2_subdev *sd,
+ struct v4l2_control *ctrl)
+{
+ struct ov_camera_module *cam_mod = to_ov_camera_module(sd);
+ int ret;
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, " id 0x%x\n", ctrl->id);
+
+ if (ctrl->id == V4L2_CID_FLASH_LED_MODE) {
+ ctrl->value = cam_mod->exp_config.flash_mode;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_FLASH_LED_MODE %d\n",
+ ctrl->value);
+ return 0;
+ }
+
+ if (IS_ERR_OR_NULL(cam_mod->active_config)) {
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "no active configuration\n");
+ return -EFAULT;
+ }
+
+ if (ctrl->id == RK_V4L2_CID_VBLANKING) {
+ ctrl->value = cam_mod->active_config->v_blanking_time_us;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "RK_V4L2_CID_VBLANKING %d\n",
+ ctrl->value);
+ return 0;
+ }
+
+ if ((cam_mod->state != OV_CAMERA_MODULE_SW_STANDBY) &&
+ (cam_mod->state != OV_CAMERA_MODULE_STREAMING)) {
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "cannot get controls when camera is off\n");
+ return -EFAULT;
+ }
+
+ if (ctrl->id == V4L2_CID_FOCUS_ABSOLUTE) {
+ struct v4l2_subdev *af_ctrl;
+
+ af_ctrl = pltfrm_camera_module_get_af_ctrl(sd);
+ if (!IS_ERR_OR_NULL(af_ctrl)) {
+ ret = v4l2_subdev_call(af_ctrl, core, g_ctrl, ctrl);
+ return ret;
+ }
+ }
+
+ if (!IS_ERR_OR_NULL(cam_mod->custom.g_ctrl)) {
+ ret = cam_mod->custom.g_ctrl(cam_mod, ctrl->id);
+ if (IS_ERR_VALUE(ret))
+ return ret;
+ }
+
+ switch (ctrl->id) {
+ case V4L2_CID_GAIN:
+ ctrl->value = cam_mod->exp_config.gain;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_GAIN %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_EXPOSURE:
+ ctrl->value = cam_mod->exp_config.exp_time;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_EXPOSURE %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_WHITE_BALANCE_TEMPERATURE:
+ ctrl->value = cam_mod->wb_config.temperature;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_WHITE_BALANCE_TEMPERATURE %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
+ ctrl->value = cam_mod->wb_config.preset_id;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_AUTOGAIN:
+ ctrl->value = cam_mod->exp_config.auto_gain;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_AUTOGAIN %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_EXPOSURE_AUTO:
+ ctrl->value = cam_mod->exp_config.auto_exp;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_EXPOSURE_AUTO %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ ctrl->value = cam_mod->wb_config.auto_wb;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_AUTO_WHITE_BALANCE %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_FOCUS_ABSOLUTE:
+ ctrl->value = cam_mod->af_config.abs_pos;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_FOCUS_ABSOLUTE %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_HFLIP:
+ case V4L2_CID_VFLIP:
+ /* TBD */
+ /* fallthrough */
+ default:
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "failed, unknown ctrl %d\n", ctrl->id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int flash_light_ctrl(
+ struct v4l2_subdev *sd,
+ struct ov_camera_module *cam_mod,
+ int value)
+{
+ return 0;
+}
+
+/* ======================================================================== */
+
+int ov_camera_module_s_ext_ctrls(
+ struct v4l2_subdev *sd,
+ struct v4l2_ext_controls *ctrls)
+{
+ int i;
+ int ctrl_cnt = 0;
+ struct ov_camera_module *cam_mod = to_ov_camera_module(sd);
+ int ret = 0;
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "\n");
+ if (ctrls->count == 0)
+ return -EINVAL;
+
+ for (i = 0; i < ctrls->count; i++) {
+ struct v4l2_ext_control *ctrl;
+ u32 ctrl_updt = 0;
+
+ ctrl = &ctrls->controls[i];
+
+ switch (ctrl->id) {
+ case V4L2_CID_GAIN:
+ ctrl_updt = OV_CAMERA_MODULE_CTRL_UPDT_GAIN;
+ cam_mod->exp_config.gain = ctrl->value;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_GAIN %d\n",
+ ctrl->value);
+ break;
+ case RK_V4L2_CID_GAIN_PERCENT:
+ ctrl_updt = OV_CAMERA_MODULE_CTRL_UPDT_GAIN;
+ cam_mod->exp_config.gain_percent = ctrl->value;
+ break;
+ case V4L2_CID_FLASH_LED_MODE:
+ ret = flash_light_ctrl(sd, cam_mod, ctrl->value);
+ if (ret == 0) {
+ cam_mod->exp_config.flash_mode = ctrl->value;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_FLASH_LED_MODE %d\n",
+ ctrl->value);
+ }
+ break;
+ case V4L2_CID_EXPOSURE:
+ ctrl_updt = OV_CAMERA_MODULE_CTRL_UPDT_EXP_TIME;
+ cam_mod->exp_config.exp_time = ctrl->value;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_EXPOSURE %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_WHITE_BALANCE_TEMPERATURE:
+ ctrl_updt = OV_CAMERA_MODULE_CTRL_UPDT_WB_TEMPERATURE;
+ cam_mod->wb_config.temperature = ctrl->value;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_WHITE_BALANCE_TEMPERATURE %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE:
+ ctrl_updt = OV_CAMERA_MODULE_CTRL_UPDT_PRESET_WB;
+ cam_mod->wb_config.preset_id = ctrl->value;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_AUTOGAIN:
+ ctrl_updt = OV_CAMERA_MODULE_CTRL_UPDT_AUTO_GAIN;
+ cam_mod->exp_config.auto_gain = ctrl->value;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_AUTOGAIN %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_EXPOSURE_AUTO:
+ ctrl_updt = OV_CAMERA_MODULE_CTRL_UPDT_AUTO_EXP;
+ cam_mod->exp_config.auto_exp = ctrl->value;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_EXPOSURE_AUTO %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ ctrl_updt = OV_CAMERA_MODULE_CTRL_UPDT_AUTO_WB;
+ cam_mod->wb_config.auto_wb = ctrl->value;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_AUTO_WHITE_BALANCE %d\n",
+ ctrl->value);
+ break;
+ case RK_V4L2_CID_AUTO_FPS:
+ cam_mod->auto_adjust_fps = ctrl->value;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "RK_V4L2_CID_AUTO_FPS %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_FOCUS_ABSOLUTE:
+ {
+ struct v4l2_subdev *af_ctrl;
+
+ af_ctrl = pltfrm_camera_module_get_af_ctrl(sd);
+ if (!IS_ERR_OR_NULL(af_ctrl)) {
+ struct v4l2_control single_ctrl;
+
+ single_ctrl.id =
+ V4L2_CID_FOCUS_ABSOLUTE;
+ single_ctrl.value = ctrl->value;
+ ret = v4l2_subdev_call(af_ctrl,
+ core, s_ctrl, &single_ctrl);
+ return ret;
+ }
+ }
+ ctrl_updt =
+ OV_CAMERA_MODULE_CTRL_UPDT_FOCUS_ABSOLUTE;
+ cam_mod->af_config.abs_pos = ctrl->value;
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "V4L2_CID_FOCUS_ABSOLUTE %d\n",
+ ctrl->value);
+ break;
+ case V4L2_CID_HFLIP:
+ if (ctrl->value)
+ cam_mod->hflip = true;
+ else
+ cam_mod->hflip = false;
+ break;
+ case V4L2_CID_VFLIP:
+ if (ctrl->value)
+ cam_mod->vflip = true;
+ else
+ cam_mod->vflip = false;
+ break;
+ default:
+ pltfrm_camera_module_pr_warn(&cam_mod->sd,
+ "ignoring unknown ctrl 0x%x\n", ctrl->id);
+ break;
+ }
+
+ if (cam_mod->state != OV_CAMERA_MODULE_SW_STANDBY &&
+ cam_mod->state != OV_CAMERA_MODULE_STREAMING)
+ cam_mod->ctrl_updt |= ctrl_updt;
+ else if (ctrl_updt)
+ ctrl_cnt++;
+ }
+
+ /* if camera module is already streaming, write through */
+ if (ctrl_cnt &&
+ (cam_mod->state == OV_CAMERA_MODULE_STREAMING ||
+ cam_mod->state == OV_CAMERA_MODULE_SW_STANDBY)) {
+ struct ov_camera_module_ext_ctrls ov_ctrls;
+
+ ov_ctrls.ctrls =
+ (struct ov_camera_module_ext_ctrl *)
+ kmalloc(ctrl_cnt * sizeof(struct ov_camera_module_ext_ctrl),
+ GFP_KERNEL);
+
+ if (ov_ctrls.ctrls) {
+ for (i = 0; i < ctrl_cnt; i++) {
+ ov_ctrls.ctrls[i].id = ctrls->controls[i].id;
+ ov_ctrls.ctrls[i].value =
+ ctrls->controls[i].value;
+ }
+
+ ov_ctrls.count = ctrl_cnt;
+
+ ret = cam_mod->custom.s_ext_ctrls(cam_mod, &ov_ctrls);
+
+ kfree(ov_ctrls.ctrls);
+ } else {
+ ret = -ENOMEM;
+ }
+ if (IS_ERR_VALUE(ret))
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "failed with error %d\n", ret);
+ }
+
+ return ret;
+}
+
+/* ======================================================================== */
+
+int ov_camera_module_s_ctrl(
+ struct v4l2_subdev *sd,
+ struct v4l2_control *ctrl)
+{
+ struct ov_camera_module *cam_mod = to_ov_camera_module(sd);
+ struct v4l2_ext_control ext_ctrl[1];
+ struct v4l2_ext_controls ext_ctrls;
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd,
+ "0x%x 0x%x\n", ctrl->id, ctrl->value);
+
+ ext_ctrl[0].id = ctrl->id;
+ ext_ctrl[0].value = ctrl->value;
+
+ ext_ctrls.count = 1;
+ ext_ctrls.controls = ext_ctrl;
+
+ return ov_camera_module_s_ext_ctrls(sd, &ext_ctrls);
+}
+
+/* ======================================================================== */
+
+long ov_camera_module_ioctl(struct v4l2_subdev *sd,
+ unsigned int cmd,
+ void *arg)
+{
+ struct ov_camera_module *cam_mod = to_ov_camera_module(sd);
+ int ret;
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "cmd: 0x%x\n", cmd);
+
+ if (cmd == RK_VIDIOC_SENSOR_MODE_DATA) {
+ struct ov_camera_module_timings ov_timings;
+ struct isp_supplemental_sensor_mode_data *timings =
+ (struct isp_supplemental_sensor_mode_data *)arg;
+
+ if (cam_mod->custom.g_timings)
+ ret = cam_mod->custom.g_timings(cam_mod, &ov_timings);
+ else
+ ret = -EPERM;
+
+ if (IS_ERR_VALUE(ret)) {
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "failed with error %d\n", ret);
+ return ret;
+ }
+
+ timings->sensor_output_width = ov_timings.sensor_output_width;
+ timings->sensor_output_height = ov_timings.sensor_output_height;
+ timings->crop_horizontal_start =
+ ov_timings.crop_horizontal_start;
+ timings->crop_vertical_start = ov_timings.crop_vertical_start;
+ timings->crop_horizontal_end = ov_timings.crop_horizontal_end;
+ timings->crop_vertical_end = ov_timings.crop_vertical_end;
+ timings->line_length_pck = ov_timings.line_length_pck;
+ timings->frame_length_lines = ov_timings.frame_length_lines;
+ timings->vt_pix_clk_freq_hz = ov_timings.vt_pix_clk_freq_hz;
+ timings->binning_factor_x = ov_timings.binning_factor_x;
+ timings->binning_factor_y = ov_timings.binning_factor_y;
+ timings->coarse_integration_time_max_margin =
+ ov_timings.coarse_integration_time_max_margin;
+ timings->coarse_integration_time_min =
+ ov_timings.coarse_integration_time_min;
+ timings->fine_integration_time_max_margin =
+ ov_timings.fine_integration_time_max_margin;
+ timings->fine_integration_time_min =
+ ov_timings.fine_integration_time_min;
+
+ if (cam_mod->custom.g_exposure_valid_frame)
+ timings->exposure_valid_frame =
+ cam_mod->custom.g_exposure_valid_frame(cam_mod);
+ if (cam_mod->exp_config.exp_time)
+ timings->exp_time = cam_mod->exp_config.exp_time;
+ else
+ timings->exp_time = ov_timings.exp_time;
+ if (cam_mod->exp_config.gain)
+ timings->gain = cam_mod->exp_config.gain;
+ else
+ timings->gain = ov_timings.gain;
+ return ret;
+ } else if (cmd == PLTFRM_CIFCAM_G_ITF_CFG) {
+ struct pltfrm_cam_itf *itf_cfg = (struct pltfrm_cam_itf *)arg;
+ struct ov_camera_module_config *config;
+
+ if (cam_mod->custom.num_configs <= 0) {
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "cam_mod->custom.num_configs is NULL, Get interface config failed!\n");
+ return -EINVAL;
+ }
+
+ if (IS_ERR_OR_NULL(cam_mod->active_config))
+ config = &cam_mod->custom.configs[0];
+ else
+ config = cam_mod->active_config;
+
+ *itf_cfg = config->itf_cfg;
+
+ pltfrm_camera_module_ioctl(sd, PLTFRM_CIFCAM_G_ITF_CFG, arg);
+ return 0;
+ } else if (cmd == PLTFRM_CIFCAM_ATTACH) {
+ ov_camera_module_init(cam_mod, &cam_mod->custom);
+ pltfrm_camera_module_ioctl(sd, cmd, arg);
+ return ov_camera_module_attach(cam_mod);
+ }
+
+ ret = pltfrm_camera_module_ioctl(sd, cmd, arg);
+ return ret;
+}
+
+/* ======================================================================== */
+
+int ov_camera_module_get_flip_mirror(
+ struct ov_camera_module *cam_mod)
+{
+ return pltfrm_camera_module_get_flip_mirror(&cam_mod->sd);
+}
+
+/* ======================================================================== */
+
+int ov_camera_module_enum_frameintervals(
+ struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_interval_enum *fie)
+{
+ struct ov_camera_module *cam_mod = to_ov_camera_module(sd);
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "%d\n", fie->index);
+
+ if (fie->index >= cam_mod->custom.num_configs)
+ return -EINVAL;
+ fie->code =
+ cam_mod->custom.configs[fie->index].frm_fmt.code;
+ fie->width =
+ cam_mod->custom.configs[fie->index].frm_fmt.width;
+ fie->height =
+ cam_mod->custom.configs[fie->index].frm_fmt.height;
+ fie->interval.numerator = cam_mod->custom.
+ configs[fie->index].frm_intrvl.interval.numerator;
+ fie->interval.denominator = cam_mod->custom.
+ configs[fie->index].frm_intrvl.interval.denominator;
+ return 0;
+}
+
+/* ======================================================================== */
+
+int ov_camera_module_write_reglist(
+ struct ov_camera_module *cam_mod,
+ const struct ov_camera_module_reg reglist[],
+ int len)
+{
+ return pltfrm_camera_module_write_reglist(&cam_mod->sd, reglist, len);
+}
+
+/* ======================================================================== */
+
+int ov_camera_module_write_reg(
+ struct ov_camera_module *cam_mod,
+ u16 reg,
+ u8 val)
+{
+ return pltfrm_camera_module_write_reg(&cam_mod->sd, reg, val);
+}
+
+/* ======================================================================== */
+
+int ov_camera_module_read_reg(
+ struct ov_camera_module *cam_mod,
+ u16 data_length,
+ u16 reg,
+ u32 *val)
+{
+ return pltfrm_camera_module_read_reg(&cam_mod->sd,
+ data_length, reg, val);
+}
+
+/* ======================================================================== */
+
+int ov_camera_module_read_reg_table(
+ struct ov_camera_module *cam_mod,
+ u16 reg,
+ u32 *val)
+{
+ int i;
+
+ if (cam_mod->state == OV_CAMERA_MODULE_STREAMING)
+ return pltfrm_camera_module_read_reg(&cam_mod->sd,
+ 1, reg, val);
+
+ if (!IS_ERR_OR_NULL(cam_mod->active_config)) {
+ for (
+ i = cam_mod->active_config->reg_table_num_entries - 1;
+ i > 0;
+ i--) {
+ if (cam_mod->active_config->reg_table[i].reg == reg) {
+ *val = cam_mod->active_config->reg_table[i].val;
+ return 0;
+ }
+ }
+ }
+
+ if (cam_mod->state == OV_CAMERA_MODULE_SW_STANDBY)
+ return pltfrm_camera_module_read_reg(&cam_mod->sd,
+ 1, reg, val);
+
+ return -EFAULT;
+}
+
+int ov_camera_module_init(struct ov_camera_module *cam_mod,
+ struct ov_camera_module_custom_config *custom)
+{
+ int ret = 0;
+
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "\n");
+
+ ov_camera_module_reset(cam_mod);
+
+ if (IS_ERR_OR_NULL(custom->start_streaming) ||
+ IS_ERR_OR_NULL(custom->stop_streaming) ||
+ IS_ERR_OR_NULL(custom->s_ctrl) ||
+ IS_ERR_OR_NULL(custom->g_ctrl)) {
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "mandatory callback function is missing\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = pltfrm_camera_module_init(&cam_mod->sd, &cam_mod->pltfm_data);
+ if (IS_ERR_VALUE(ret))
+ goto err;
+
+ ret = pltfrm_camera_module_set_pin_state(&cam_mod->sd,
+ PLTFRM_CAMERA_MODULE_PIN_PD,
+ PLTFRM_CAMERA_MODULE_PIN_STATE_INACTIVE);
+ ret = pltfrm_camera_module_set_pin_state(&cam_mod->sd,
+ PLTFRM_CAMERA_MODULE_PIN_RESET,
+ PLTFRM_CAMERA_MODULE_PIN_STATE_ACTIVE);
+ if (IS_ERR_VALUE(ret)) {
+ ov_camera_module_release(cam_mod);
+ goto err;
+ }
+
+ return 0;
+err:
+ pltfrm_camera_module_pr_err(&cam_mod->sd,
+ "failed with error %d\n", ret);
+ return ret;
+}
+
+void ov_camera_module_release(struct ov_camera_module *cam_mod)
+{
+ pltfrm_camera_module_pr_debug(&cam_mod->sd, "\n");
+
+ if (cam_mod->otp_work.wq) {
+ flush_workqueue(cam_mod->otp_work.wq);
+ destroy_workqueue(cam_mod->otp_work.wq);
+ cam_mod->otp_work.wq = NULL;
+ }
+
+ cam_mod->custom.configs = NULL;
+
+ pltfrm_camera_module_release(&cam_mod->sd);
+ v4l2_device_unregister_subdev(&cam_mod->sd);
+}
--- /dev/null
+/*
+ * ov_camera_module.h
+ *
+ * Generic omnivision sensor driver
+ *
+ * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd.
+ *
+ * Copyright (C) 2012-2014 Intel Mobile Communications GmbH
+ *
+ * Copyright (C) 2008 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+
+#ifndef OV_CAMERA_MODULE_H
+#define OV_CAMERA_MODULE_H
+#include <linux/workqueue.h>
+#include <linux/platform_data/rk_isp10_platform_camera_module.h>
+#include <linux/platform_data/rk_isp10_platform.h>
+
+/*
+ * TODO: references to v4l2 should be reomved from here and go into a
+ * platform dependent wrapper
+ */
+
+#define OV_CAMERA_MODULE_REG_TYPE_DATA PLTFRM_CAMERA_MODULE_REG_TYPE_DATA
+#define OV_CAMERA_MODULE_REG_TYPE_TIMEOUT PLTFRM_CAMERA_MODULE_REG_TYPE_TIMEOUT
+#define ov_camera_module_csi_config
+#define ov_camera_module_reg pltfrm_camera_module_reg
+#define OV_FLIP_BIT_MASK 0x2
+#define OV_MIRROR_BIT_MASK 0x1
+
+#define OV_CAMERA_MODULE_CTRL_UPDT_GAIN 0x01
+#define OV_CAMERA_MODULE_CTRL_UPDT_EXP_TIME 0x02
+#define OV_CAMERA_MODULE_CTRL_UPDT_WB_TEMPERATURE 0x04
+#define OV_CAMERA_MODULE_CTRL_UPDT_AUTO_WB 0x08
+#define OV_CAMERA_MODULE_CTRL_UPDT_AUTO_GAIN 0x10
+#define OV_CAMERA_MODULE_CTRL_UPDT_AUTO_EXP 0x20
+#define OV_CAMERA_MODULE_CTRL_UPDT_FOCUS_ABSOLUTE 0x40
+#define OV_CAMERA_MODULE_CTRL_UPDT_PRESET_WB 0x80
+
+enum ov_camera_module_state {
+ OV_CAMERA_MODULE_POWER_OFF = 0,
+ OV_CAMERA_MODULE_HW_STANDBY = 1,
+ OV_CAMERA_MODULE_SW_STANDBY = 2,
+ OV_CAMERA_MODULE_STREAMING = 3
+};
+
+struct ov_camera_module;
+
+struct ov_camera_module_timings {
+ /* public */
+ u32 coarse_integration_time_min;
+ u32 coarse_integration_time_max_margin;
+ u32 fine_integration_time_min;
+ u32 fine_integration_time_max_margin;
+ u32 frame_length_lines;
+ u32 line_length_pck;
+ u32 vt_pix_clk_freq_hz;
+ u32 sensor_output_width;
+ u32 sensor_output_height;
+ u32 crop_horizontal_start; /* Sensor crop start cord. (x0,y0) */
+ u32 crop_vertical_start;
+ u32 crop_horizontal_end; /* Sensor crop end cord. (x1,y1) */
+ u32 crop_vertical_end;
+ u8 binning_factor_x;
+ u8 binning_factor_y;
+ u32 exp_time;
+ u32 gain;
+};
+
+struct ov_camera_module_config {
+ const char *name;
+ struct v4l2_mbus_framefmt frm_fmt;
+ struct v4l2_subdev_frame_interval frm_intrvl;
+ bool auto_exp_enabled;
+ bool auto_gain_enabled;
+ bool auto_wb_enabled;
+ struct ov_camera_module_reg *reg_table;
+ u32 reg_table_num_entries;
+ struct ov_camera_module_reg *reg_diff_table;
+ u32 reg_diff_table_num_entries;
+ u32 v_blanking_time_us;
+ u32 line_length_pck;
+ u32 frame_length_lines;
+ struct ov_camera_module_timings timings;
+ bool soft_reset;
+ bool ignore_measurement_check;
+
+ struct pltfrm_cam_itf itf_cfg;
+};
+
+struct ov_camera_module_exp_config {
+ s32 exp_time;
+ bool auto_exp;
+ u16 gain;
+ u16 gain_percent;
+ bool auto_gain;
+ enum v4l2_flash_led_mode flash_mode;
+};
+
+struct ov_camera_module_wb_config {
+ u32 temperature;
+ u32 preset_id;
+ bool auto_wb;
+};
+
+struct ov_camera_module_af_config {
+ u32 abs_pos;
+ u32 rel_pos;
+};
+
+struct ov_camera_module_ext_ctrl {
+ /* public */
+ u32 id;
+ u32 value;
+ __u32 reserved2[1];
+};
+
+struct ov_camera_module_ext_ctrls {
+ /* public */
+ u32 count;
+ struct ov_camera_module_ext_ctrl *ctrls;
+};
+
+/*
+ * start_streaming: (mandatory) will be called when sensor should be
+ * put into streaming mode right after the base config has been
+ * written to the sensor. After a successful call of this function
+ * the sensor should start delivering frame data.
+ *
+ * stop_streaming: (mandatory) will be called when sensor should stop
+ * delivering data. After a successful call of this function the
+ * sensor should not deliver any more frame data.
+ *
+ * check_camera_id: (optional) will be called when the sensor is
+ * powered on. If provided should check the sensor ID/version
+ * required by the custom driver. Register access should be
+ * possible when this function is invoked.
+ *
+ * s_ctrl: (mandatory) will be called at the successful end of
+ * ov_camera_module_s_ctrl with the ctrl_id as argument.
+ *
+ * priv: (optional) for private data used by the custom driver.
+ */
+struct ov_camera_module_custom_config {
+ int (*start_streaming)(struct ov_camera_module *cam_mod);
+ int (*stop_streaming)(struct ov_camera_module *cam_mod);
+ int (*check_camera_id)(struct ov_camera_module *cam_mod);
+ int (*s_ctrl)(struct ov_camera_module *cam_mod, u32 ctrl_id);
+ int (*g_ctrl)(struct ov_camera_module *cam_mod, u32 ctrl_id);
+ int (*g_timings)(struct ov_camera_module *cam_mod,
+ struct ov_camera_module_timings *timings);
+ int (*g_exposure_valid_frame)(struct ov_camera_module *cam_mod);
+ int (*s_ext_ctrls)(struct ov_camera_module *cam_mod,
+ struct ov_camera_module_ext_ctrls *ctrls);
+ int (*set_flip)(
+ struct ov_camera_module *cam_mod,
+ struct pltfrm_camera_module_reg reglist[],
+ int len);
+ int (*init_common)(struct ov_camera_module *cam_mod);
+ int (*read_otp)(struct ov_camera_module *cam_mod);
+ struct ov_camera_module_config *configs;
+ u32 num_configs;
+ u32 power_up_delays_ms[3];
+ void *priv;
+};
+
+struct ov_camera_module_otp_work {
+ struct work_struct work;
+ struct workqueue_struct *wq;
+ void *cam_mod;
+};
+
+struct ov_camera_module {
+ /* public */
+ struct v4l2_subdev sd;
+ struct v4l2_mbus_framefmt frm_fmt;
+ struct v4l2_subdev_frame_interval frm_intrvl;
+ struct ov_camera_module_exp_config exp_config;
+ struct ov_camera_module_wb_config wb_config;
+ struct ov_camera_module_af_config af_config;
+ struct ov_camera_module_custom_config custom;
+ enum ov_camera_module_state state;
+ enum ov_camera_module_state state_before_suspend;
+ struct ov_camera_module_config *active_config;
+ struct ov_camera_module_otp_work otp_work;
+ u32 ctrl_updt;
+ u32 vts_cur;
+ u32 vts_min;
+ bool auto_adjust_fps;
+ bool update_config;
+ bool frm_fmt_valid;
+ bool frm_intrvl_valid;
+ bool hflip;
+ bool vflip;
+ u32 rotation;
+ void *pltfm_data;
+ bool inited;
+};
+
+#define ov_camera_module_pr_info(cam_mod, fmt, arg...) \
+ pltfrm_camera_module_pr_info(&(cam_mod)->sd, fmt, ## arg)
+#define ov_camera_module_pr_debug(cam_mod, fmt, arg...) \
+ pltfrm_camera_module_pr_debug(&(cam_mod)->sd, fmt, ## arg)
+#define ov_camera_module_pr_warn(cam_mod, fmt, arg...) \
+ pltfrm_camera_module_pr_warn(&(cam_mod)->sd, fmt, ## arg)
+#define ov_camera_module_pr_err(cam_mod, fmt, arg...) \
+ pltfrm_camera_module_pr_err(&(cam_mod)->sd, fmt, ## arg)
+
+int ov_camera_module_write_reglist(
+ struct ov_camera_module *cam_mod,
+ const struct ov_camera_module_reg reglist[],
+ int len);
+
+int ov_camera_module_write_reg(
+ struct ov_camera_module *cam_mod,
+ u16 reg,
+ u8 val);
+
+int ov_camera_module_read_reg(
+ struct ov_camera_module *cam_mod,
+ u16 data_length,
+ u16 reg,
+ u32 *val);
+
+int ov_camera_module_read_reg_table(
+ struct ov_camera_module *cam_mod,
+ u16 reg,
+ u32 *val);
+
+int ov_camera_module_s_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format);
+
+int ov_camera_module_g_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_format *format);
+
+int ov_camera_module_s_frame_interval(
+ struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *interval);
+
+int ov_camera_module_s_stream(
+ struct v4l2_subdev *sd,
+ int enable);
+
+int ov_camera_module_s_power(
+ struct v4l2_subdev *sd,
+ int on);
+
+int ov_camera_module_g_ctrl(
+ struct v4l2_subdev *sd,
+ struct v4l2_control *ctrl);
+
+int ov_camera_module_s_ctrl(
+ struct v4l2_subdev *sd,
+ struct v4l2_control *ctrl);
+
+int ov_camera_module_s_ext_ctrls(
+ struct v4l2_subdev *sd,
+ struct v4l2_ext_controls *ctrls);
+
+int ov_camera_module_enum_frameintervals(
+ struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_interval_enum *fie);
+
+int ov_camera_module_init(
+ struct ov_camera_module *cam_mod,
+ struct ov_camera_module_custom_config *custom);
+
+void ov_camera_module_release(
+ struct ov_camera_module *cam_mod);
+
+long ov_camera_module_ioctl(struct v4l2_subdev *sd,
+ unsigned int cmd,
+ void *arg);
+
+int ov_camera_module_get_flip_mirror(
+ struct ov_camera_module *cam_mod);
+#endif
--- /dev/null
+/*
+ * rk_camera_module.c
+ * (Based on Intel driver for sofiaxxx)
+ *
+ * Copyright (C) 2015 Intel Mobile Communications GmbH
+ * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef CONFIG_OF
+#error "this file requires device tree support"
+#endif
+
+#ifndef SOFIA_3G_CAMERA_MODULE_H
+#define SOFIA_3G_CAMERA_MODULE_H
+
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#ifdef CONFIG_PLATFORM_DEVICE_PM
+#include <linux/device_state_pm.h>
+#endif
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
+#include <media/v4l2-subdev.h>
+#include <linux/videodev2.h>
+#include <linux/lcm.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/platform_data/rk_isp10_platform_camera_module.h>
+#include <linux/platform_data/rk_isp10_platform.h>
+#include <media/v4l2-controls_rockchip.h>
+
+#define OF_OV_GPIO_PD "rockchip,pd-gpio"
+#define OF_OV_GPIO_PWR "rockchip,pwr-gpio"
+#define OF_OV_GPIO_FLASH "rockchip,flash-gpio"
+#define OF_OV_GPIO_TORCH "rockchip,torch-gpio"
+#define OF_OV_GPIO_RESET "rockchip,rst-gpio"
+
+#define OF_CAMERA_MODULE_NAME "rockchip,camera-module-name"
+#define OF_CAMERA_MODULE_LEN_NAME "rockchip,camera-module-len-name"
+#define OF_CAMERA_MODULE_FOV_H "rockchip,camera-module-fov-h"
+#define OF_CAMERA_MODULE_FOV_V "rockchip,camera-module-fov-v"
+#define OF_CAMERA_MODULE_ORIENTATION "rockchip,camera-module-orientation"
+#define OF_CAMERA_MODULE_FOCAL_LENGTH "rockchip,camera-module-focal-length"
+#define OF_CAMERA_MODULE_FOCUS_DISTANCE "rockchip,camera-module-focus-distance"
+#define OF_CAMERA_MODULE_IQ_MIRROR "rockchip,camera-module-iq-mirror"
+#define OF_CAMERA_MODULE_IQ_FLIP "rockchip,camera-module-iq-flip"
+#define OF_CAMERA_MODULE_FLIP "rockchip,camera-module-flip"
+#define OF_CAMERA_MODULE_MIRROR "rockchip,camera-module-mirror"
+#define OF_CAMERA_FLASH_SUPPORT "rockchip,camera-module-flash-support"
+#define OF_CAMERA_FLASH_EXP_PERCENT "rockchip,camera-module-flash-exp-percent"
+#define OF_CAMERA_FLASH_TURN_ON_TIME "rockchip,camera-module-flash-turn-on-time"
+#define OF_CAMERA_FLASH_ON_TIMEOUT "rockchip,camera-module-flash-on-timeout"
+#define OF_CAMERA_MODULE_DEFRECT0 "rockchip,camera-module-defrect0"
+#define OF_CAMERA_MODULE_DEFRECT1 "rockchip,camera-module-defrect1"
+#define OF_CAMERA_MODULE_DEFRECT2 "rockchip,camera-module-defrect2"
+#define OF_CAMERA_MODULE_DEFRECT3 "rockchip,camera-module-defrect3"
+#define OF_CAMERA_MODULE_MIPI_DPHY_INDEX "rockchip,camera-module-mipi-dphy-index"
+
+#define OF_CAMERA_MODULE_REGULATORS "rockchip,camera-module-regulator-names"
+#define OF_CAMERA_MODULE_REGULATOR_VOLTAGES "rockchip,camera-module-regulator-voltages"
+#define OF_CAMERA_MODULE_MCLK_NAME "rockchip,camera-module-mclk-name"
+#define OF_CAMERA_PINCTRL_STATE_DEFAULT "rockchip,camera_default"
+#define OF_CAMERA_PINCTRL_STATE_SLEEP "rockchip,camera_sleep"
+
+const char *PLTFRM_CAMERA_MODULE_PIN_PD = OF_OV_GPIO_PD;
+const char *PLTFRM_CAMERA_MODULE_PIN_PWR = OF_OV_GPIO_PWR;
+const char *PLTFRM_CAMERA_MODULE_PIN_FLASH = OF_OV_GPIO_FLASH;
+const char *PLTFRM_CAMERA_MODULE_PIN_TORCH = OF_OV_GPIO_TORCH;
+const char *PLTFRM_CAMERA_MODULE_PIN_RESET = OF_OV_GPIO_RESET;
+
+#define I2C_M_WR 0
+#define I2C_MSG_MAX 300
+#define I2C_DATA_MAX (I2C_MSG_MAX * 3)
+
+struct pltfrm_camera_module_gpio {
+ int pltfrm_gpio;
+ const char *label;
+ enum of_gpio_flags active_low;
+};
+
+struct pltfrm_camera_module_regulator {
+ struct regulator *regulator;
+ unsigned int min_uV;
+ unsigned int max_uV;
+};
+
+struct pltfrm_camera_module_regulators {
+ unsigned int cnt;
+ struct pltfrm_camera_module_regulator *regulator;
+};
+
+struct pltfrm_camera_module_fl {
+ const char *flash_driver_name;
+ /* flash ,torch */
+ char fl_init_status;
+ struct pltfrm_camera_module_gpio *fl_flash;
+ struct pltfrm_camera_module_gpio *fl_torch;
+ struct v4l2_subdev *flsh_ctrl;
+};
+
+struct pltfrm_camera_module_info_s {
+ const char *module_name;
+ const char *len_name;
+ const char *fov_h;
+ const char *fov_v;
+ const char *focal_length;
+ const char *focus_distance;
+ int facing;
+ int orientation;
+ bool iq_mirror;
+ bool iq_flip;
+ int flip;
+ int mirror;
+ int flash_support;
+ int flash_exp_percent;
+ int flash_turn_on_time;
+ int flash_on_timeout;
+};
+
+struct pltfrm_camera_module_mipi {
+ unsigned int dphy_index;
+};
+
+struct pltfrm_camera_module_itf {
+ union {
+ struct pltfrm_camera_module_mipi mipi;
+ } itf;
+};
+
+struct pltfrm_camera_module_data {
+ struct pltfrm_camera_module_gpio gpios[6];
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *pins_default;
+ struct pinctrl_state *pins_sleep;
+ struct v4l2_subdev *af_ctrl;
+ /* move to struct pltfrm_camera_module_fl */
+ /* const char *flash_driver_name; */
+ struct pltfrm_camera_module_fl fl_ctrl;
+
+ struct pltfrm_camera_module_info_s info;
+ struct pltfrm_camera_module_itf itf;
+ struct pltfrm_cam_defrect defrects[4];
+ struct clk *mclk;
+ struct pltfrm_soc_cfg *soc_cfg;
+ struct pltfrm_camera_module_regulators regulators;
+
+ void *priv;
+};
+
+/* ======================================================================== */
+
+static int pltfrm_camera_module_set_pinctrl_state(
+ struct v4l2_subdev *sd,
+ struct pinctrl_state *state)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct pltfrm_camera_module_data *pdata =
+ dev_get_platdata(&client->dev);
+ int ret = 0;
+
+ if (!IS_ERR_OR_NULL(state)) {
+ ret = pinctrl_select_state(pdata->pinctrl, state);
+ if (IS_ERR_VALUE(ret))
+ pltfrm_camera_module_pr_debug(sd,
+ "could not set pins\n");
+ }
+
+ return ret;
+}
+
+static int pltfrm_camera_module_init_gpio(
+ struct v4l2_subdev *sd)
+{
+ int ret = 0;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct pltfrm_camera_module_data *pdata =
+ dev_get_platdata(&client->dev);
+ int i = 0;
+
+ ret = pltfrm_camera_module_set_pinctrl_state(sd, pdata->pins_default);
+ if (IS_ERR_VALUE(ret))
+ goto err;
+
+ for (i = 0; i < ARRAY_SIZE(pdata->gpios); i++) {
+ if (gpio_is_valid(pdata->gpios[i].pltfrm_gpio)) {
+ if (pdata->gpios[i].label ==
+ PLTFRM_CAMERA_MODULE_PIN_FLASH ||
+ pdata->gpios[i].label ==
+ PLTFRM_CAMERA_MODULE_PIN_TORCH) {
+ if (pdata->fl_ctrl.fl_init_status &&
+ pdata->fl_ctrl.fl_flash->pltfrm_gpio ==
+ pdata->fl_ctrl.fl_torch->pltfrm_gpio) {
+ pltfrm_camera_module_pr_info(
+ sd,
+ "fl gpio has been inited, continue!\n");
+ continue;
+ }
+ pdata->fl_ctrl.fl_init_status = 1;
+ }
+
+ pltfrm_camera_module_pr_debug(
+ sd,
+ "requesting GPIO #%d ('%s')\n",
+ pdata->gpios[i].pltfrm_gpio,
+ pdata->gpios[i].label);
+ ret = gpio_request_one(
+ pdata->gpios[i].pltfrm_gpio,
+ GPIOF_DIR_OUT,
+ pdata->gpios[i].label);
+ if (IS_ERR_VALUE(ret)) {
+ if ((pdata->gpios[i].label ==
+ PLTFRM_CAMERA_MODULE_PIN_RESET) ||
+ (pdata->gpios[i].label ==
+ PLTFRM_CAMERA_MODULE_PIN_PWR)) {
+ pltfrm_camera_module_pr_warn(sd,
+ "GPIO #%d ('%s') may be reused!\n",
+ pdata->gpios[i].pltfrm_gpio,
+ pdata->gpios[i].label);
+ } else {
+ pltfrm_camera_module_pr_err(sd,
+ "failed to request GPIO #%d ('%s')\n",
+ pdata->gpios[i].pltfrm_gpio,
+ pdata->gpios[i].label);
+ goto err;
+ }
+ }
+
+ if (pdata->gpios[i].label ==
+ PLTFRM_CAMERA_MODULE_PIN_PD)
+ ret = pltfrm_camera_module_set_pin_state(sd,
+ pdata->gpios[i].label,
+ PLTFRM_CAMERA_MODULE_PIN_STATE_INACTIVE);
+ else if (pdata->gpios[i].label ==
+ PLTFRM_CAMERA_MODULE_PIN_RESET)
+ ret = pltfrm_camera_module_set_pin_state(sd,
+ pdata->gpios[i].label,
+ PLTFRM_CAMERA_MODULE_PIN_STATE_ACTIVE);
+ else
+ ret = pltfrm_camera_module_set_pin_state(sd,
+ pdata->gpios[i].label,
+ PLTFRM_CAMERA_MODULE_PIN_STATE_INACTIVE
+ );
+ }
+ }
+ return 0;
+err:
+ pltfrm_camera_module_pr_err(sd, "failed with error %d\n", ret);
+ for (; i < ARRAY_SIZE(pdata->gpios); i++)
+ pdata->gpios[i].pltfrm_gpio = -1;
+
+ return ret;
+}
+
+static struct pltfrm_camera_module_data *pltfrm_camera_module_get_data(
+ struct v4l2_subdev *sd)
+{
+ int ret = 0;
+ int elem_size, elem_index;
+ const char *str = "";
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct device_node *np = of_node_get(client->dev.of_node);
+ struct device_node *af_ctrl_node = NULL;
+ struct i2c_client *af_ctrl_client = NULL;
+ struct device_node *fl_ctrl_node = NULL;
+ struct i2c_client *fl_ctrl_client = NULL;
+ struct pltfrm_camera_module_data *pdata = NULL;
+ struct property *prop;
+
+ pltfrm_camera_module_pr_debug(sd, "\n");
+
+ pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
+ if (IS_ERR_OR_NULL(pdata)) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ client->dev.platform_data = pdata;
+
+ ret = of_property_read_string(np, OF_CAMERA_MODULE_MCLK_NAME, &str);
+ if (ret) {
+ pltfrm_camera_module_pr_err(sd,
+ "cannot not get camera-module-mclk-name property of node %s\n",
+ np->name);
+ ret = -ENODEV;
+ goto err;
+ }
+
+ pdata->mclk = devm_clk_get(&client->dev, str);
+ if (IS_ERR_OR_NULL(pdata->mclk)) {
+ pltfrm_camera_module_pr_err(sd,
+ "cannot not get %s property of node %s\n",
+ str, np->name);
+ ret = -ENODEV;
+ goto err;
+ }
+
+ ret = of_property_read_string(np,
+ "rockchip,camera-module-facing", &str);
+ if (ret) {
+ pltfrm_camera_module_pr_err(sd,
+ "cannot not get camera-module-facing property of node %s\n",
+ np->name);
+ } else {
+ pltfrm_camera_module_pr_debug(sd,
+ "camera module camera-module-facing driver is %s\n",
+ str);
+ }
+ pdata->info.facing = -1;
+ if (!strcmp(str, "back"))
+ pdata->info.facing = 0;
+ else if (!strcmp(str, "front"))
+ pdata->info.facing = 1;
+
+ ret = of_property_read_string(np, "rockchip,flash-driver",
+ &pdata->fl_ctrl.flash_driver_name);
+ if (ret) {
+ pltfrm_camera_module_pr_debug(sd,
+ "cannot not get flash-driver property of node %s\n",
+ np->name);
+ pdata->fl_ctrl.flash_driver_name = "0";
+ } else {
+ pltfrm_camera_module_pr_info(sd,
+ "camera module flash driver is %s\n",
+ (char *)pdata->fl_ctrl.flash_driver_name);
+
+ /*parse flash node info*/
+ fl_ctrl_node = of_parse_phandle(np, "rockchip,fl-ctrl", 0);
+ if (!IS_ERR_OR_NULL(fl_ctrl_node)) {
+ fl_ctrl_client =
+ of_find_i2c_device_by_node(fl_ctrl_node);
+ of_node_put(fl_ctrl_node);
+ if (IS_ERR_OR_NULL(fl_ctrl_client)) {
+ pltfrm_camera_module_pr_err(sd,
+ "cannot not get node\n");
+ ret = -EFAULT;
+ goto err;
+ }
+ pdata->fl_ctrl.flsh_ctrl =
+ i2c_get_clientdata(fl_ctrl_client);
+ if (IS_ERR_OR_NULL(pdata->fl_ctrl.flsh_ctrl)) {
+ pltfrm_camera_module_pr_warn(sd,
+ "cannot not get camera i2c client, maybe not yet created, deferring device probing...\n");
+ ret = -EPROBE_DEFER;
+ goto err;
+ }
+ pltfrm_camera_module_pr_info(sd,
+ "camera module has flash driver %s\n",
+ pltfrm_dev_string(pdata->fl_ctrl.flsh_ctrl));
+ }
+ }
+
+ af_ctrl_node = of_parse_phandle(np, "rockchip,af-ctrl", 0);
+ if (!IS_ERR_OR_NULL(af_ctrl_node)) {
+ af_ctrl_client = of_find_i2c_device_by_node(af_ctrl_node);
+ of_node_put(af_ctrl_node);
+ if (IS_ERR_OR_NULL(af_ctrl_client)) {
+ pltfrm_camera_module_pr_err(sd,
+ "cannot not get node\n");
+ ret = -EFAULT;
+ goto err;
+ }
+ pdata->af_ctrl = i2c_get_clientdata(af_ctrl_client);
+ if (IS_ERR_OR_NULL(pdata->af_ctrl)) {
+ pltfrm_camera_module_pr_warn(sd,
+ "cannot not get camera i2c client, maybe not yet created, deferring device probing...\n");
+ ret = -EPROBE_DEFER;
+ goto err;
+ }
+ pltfrm_camera_module_pr_info(sd,
+ "camera module has auto focus controller %s\n",
+ pltfrm_dev_string(pdata->af_ctrl));
+ }
+
+ pdata->pinctrl = devm_pinctrl_get(&client->dev);
+ if (!IS_ERR(pdata->pinctrl)) {
+ pdata->pins_default = pinctrl_lookup_state(
+ pdata->pinctrl,
+ OF_CAMERA_PINCTRL_STATE_DEFAULT);
+ if (IS_ERR(pdata->pins_default))
+ pltfrm_camera_module_pr_warn(sd,
+ "could not get default pinstate\n");
+
+ pdata->pins_sleep = pinctrl_lookup_state(
+ pdata->pinctrl, OF_CAMERA_PINCTRL_STATE_SLEEP);
+ if (IS_ERR(pdata->pins_sleep))
+ pltfrm_camera_module_pr_warn(sd,
+ "could not get sleep pinstate\n");
+ }
+
+ elem_size = of_property_count_elems_of_size(
+ np,
+ OF_CAMERA_MODULE_REGULATOR_VOLTAGES,
+ sizeof(u32));
+ prop = of_find_property(
+ np,
+ OF_CAMERA_MODULE_REGULATORS,
+ NULL);
+ if (!IS_ERR_VALUE(elem_size) &&
+ !IS_ERR_OR_NULL(prop)) {
+ struct pltfrm_camera_module_regulator *regulator;
+
+ pdata->regulators.regulator = devm_kzalloc(&client->dev,
+ elem_size *
+ sizeof(struct pltfrm_camera_module_regulator),
+ GFP_KERNEL);
+ if (!pdata->regulators.regulator) {
+ pltfrm_camera_module_pr_err(sd,
+ "could not malloc pltfrm_camera_module_regulator\n");
+ goto err;
+ }
+ pdata->regulators.cnt = elem_size;
+ str = NULL;
+ elem_index = 0;
+ regulator = pdata->regulators.regulator;
+ do {
+ str = of_prop_next_string(prop, str);
+ if (!str) {
+ pltfrm_camera_module_pr_err(sd,
+ "%s is not match %s in dts\n",
+ OF_CAMERA_MODULE_REGULATORS,
+ OF_CAMERA_MODULE_REGULATOR_VOLTAGES);
+ break;
+ }
+ regulator->regulator =
+ devm_regulator_get_optional(&client->dev, str);
+ if (IS_ERR(regulator->regulator))
+ pltfrm_camera_module_pr_err(sd,
+ "devm_regulator_get %s failed\n",
+ str);
+ of_property_read_u32_index(
+ np,
+ OF_CAMERA_MODULE_REGULATOR_VOLTAGES,
+ elem_index++,
+ ®ulator->min_uV);
+ regulator->max_uV = regulator->min_uV;
+ regulator++;
+ } while (--elem_size);
+ }
+ pdata->gpios[0].label = PLTFRM_CAMERA_MODULE_PIN_PD;
+ pdata->gpios[0].pltfrm_gpio = of_get_named_gpio_flags(
+ np,
+ pdata->gpios[0].label,
+ 0,
+ &pdata->gpios[0].active_low);
+
+ pdata->gpios[1].label = PLTFRM_CAMERA_MODULE_PIN_PWR;
+ pdata->gpios[1].pltfrm_gpio = of_get_named_gpio_flags(
+ np,
+ pdata->gpios[1].label,
+ 0,
+ &pdata->gpios[1].active_low);
+
+ pdata->gpios[2].label = PLTFRM_CAMERA_MODULE_PIN_FLASH;
+ pdata->gpios[2].pltfrm_gpio = of_get_named_gpio_flags(
+ np,
+ pdata->gpios[2].label,
+ 0,
+ &pdata->gpios[2].active_low);
+
+ /*set fl_ctrl flash reference*/
+ pdata->fl_ctrl.fl_flash = &pdata->gpios[2];
+
+ pdata->gpios[3].label = PLTFRM_CAMERA_MODULE_PIN_TORCH;
+ pdata->gpios[3].pltfrm_gpio = of_get_named_gpio_flags(
+ np,
+ pdata->gpios[3].label,
+ 0,
+ &pdata->gpios[3].active_low);
+
+ /*set fl_ctrl torch reference*/
+ pdata->fl_ctrl.fl_torch = &pdata->gpios[3];
+
+ pdata->gpios[4].label = PLTFRM_CAMERA_MODULE_PIN_RESET;
+ pdata->gpios[4].pltfrm_gpio = of_get_named_gpio_flags(
+ np,
+ pdata->gpios[4].label,
+ 0,
+ &pdata->gpios[4].active_low);
+
+ ret = of_property_read_string(np, OF_CAMERA_MODULE_NAME,
+ &pdata->info.module_name);
+ ret |= of_property_read_string(np, OF_CAMERA_MODULE_LEN_NAME,
+ &pdata->info.len_name);
+ if (ret) {
+ pltfrm_camera_module_pr_err(
+ sd,
+ "could not get module %s and %s from dts!\n",
+ OF_CAMERA_MODULE_NAME,
+ OF_CAMERA_MODULE_LEN_NAME);
+ }
+
+ if (of_property_read_u32(
+ np,
+ OF_CAMERA_MODULE_ORIENTATION,
+ (unsigned int *)&pdata->info.orientation)) {
+ pdata->info.orientation = -1;
+ pltfrm_camera_module_pr_err(
+ sd,
+ "could not get module %s from dts!\n",
+ OF_CAMERA_MODULE_ORIENTATION);
+ }
+
+ if (of_property_read_u32(
+ np,
+ OF_CAMERA_MODULE_FLIP,
+ (unsigned int *)&pdata->info.flip)) {
+ pdata->info.flip = -1;
+ pltfrm_camera_module_pr_err(
+ sd,
+ "could not get module %s from dts!\n",
+ OF_CAMERA_MODULE_FLIP);
+ }
+
+ if (of_property_read_u32(
+ np,
+ OF_CAMERA_MODULE_MIRROR,
+ (unsigned int *)&pdata->info.mirror)) {
+ pdata->info.mirror = -1;
+ pltfrm_camera_module_pr_err(
+ sd,
+ "could not get module %s from dts!\n",
+ OF_CAMERA_MODULE_MIRROR);
+ }
+
+ if (of_property_read_u32(
+ np,
+ OF_CAMERA_FLASH_SUPPORT,
+ (unsigned int *)&pdata->info.flash_support)) {
+ pdata->info.flash_support = -1;
+ pltfrm_camera_module_pr_err(
+ sd,
+ "could not get module %s from dts!\n",
+ OF_CAMERA_FLASH_SUPPORT);
+ }
+
+ ret = of_property_read_string(np, OF_CAMERA_MODULE_FOV_H,
+ &pdata->info.fov_h);
+ ret |= of_property_read_string(np, OF_CAMERA_MODULE_FOV_V,
+ &pdata->info.fov_v);
+ if (ret) {
+ pltfrm_camera_module_pr_debug(
+ sd,
+ "could not get module %s and %s from dts!",
+ OF_CAMERA_MODULE_FOV_H,
+ OF_CAMERA_MODULE_FOV_V);
+ }
+
+ ret = of_property_read_string(np, OF_CAMERA_MODULE_FOCAL_LENGTH,
+ &pdata->info.focal_length);
+ if (ret) {
+ pltfrm_camera_module_pr_debug(
+ sd,
+ "could not get %s from dts!\n",
+ OF_CAMERA_MODULE_FOCAL_LENGTH);
+ }
+ ret = of_property_read_string(np, OF_CAMERA_MODULE_FOCUS_DISTANCE,
+ &pdata->info.focus_distance);
+ if (ret) {
+ pltfrm_camera_module_pr_debug(
+ sd,
+ "could not get %s from dts!\n",
+ OF_CAMERA_MODULE_FOCUS_DISTANCE);
+ }
+
+ ret = 0;
+ of_property_read_u32(np, OF_CAMERA_MODULE_IQ_MIRROR, &ret);
+ pdata->info.iq_mirror = (ret == 0) ? false : true;
+
+ ret = 0;
+ of_property_read_u32(np, OF_CAMERA_MODULE_IQ_FLIP, &ret);
+ pdata->info.iq_flip = (ret == 0) ? false : true;
+
+ if (of_property_read_u32(
+ np,
+ OF_CAMERA_FLASH_EXP_PERCENT,
+ (unsigned int *)&pdata->info.flash_exp_percent)) {
+ pdata->info.flash_exp_percent = -1;
+ pltfrm_camera_module_pr_debug(
+ sd,
+ "could not get module %s from dts!\n",
+ OF_CAMERA_FLASH_EXP_PERCENT);
+ }
+
+ if (of_property_read_u32(
+ np,
+ OF_CAMERA_FLASH_TURN_ON_TIME,
+ (unsigned int *)&pdata->info.flash_turn_on_time)) {
+ pdata->info.flash_turn_on_time = -1;
+ pltfrm_camera_module_pr_debug(
+ sd,
+ "could not get module %s from dts!\n",
+ OF_CAMERA_FLASH_TURN_ON_TIME);
+ }
+
+ if (of_property_read_u32(
+ np,
+ OF_CAMERA_FLASH_ON_TIMEOUT,
+ (unsigned int *)&pdata->info.flash_on_timeout)) {
+ pdata->info.flash_on_timeout = -1;
+ pltfrm_camera_module_pr_debug(
+ sd,
+ "could not get module %s from dts!\n",
+ OF_CAMERA_FLASH_ON_TIMEOUT);
+ }
+
+ of_property_read_u32_array(
+ np,
+ OF_CAMERA_MODULE_DEFRECT0,
+ (unsigned int *)&pdata->defrects[0],
+ 6);
+ of_property_read_u32_array(
+ np,
+ OF_CAMERA_MODULE_DEFRECT1,
+ (unsigned int *)&pdata->defrects[1],
+ 6);
+ of_property_read_u32_array(
+ np,
+ OF_CAMERA_MODULE_DEFRECT2,
+ (unsigned int *)&pdata->defrects[2],
+ 6);
+ of_property_read_u32_array(
+ np,
+ OF_CAMERA_MODULE_DEFRECT3,
+ (unsigned int *)&pdata->defrects[3],
+ 6);
+
+ if (of_property_read_u32(
+ np,
+ OF_CAMERA_MODULE_MIPI_DPHY_INDEX,
+ (unsigned int *)&pdata->itf.itf.mipi.dphy_index)) {
+ pdata->itf.itf.mipi.dphy_index = -1;
+ pltfrm_camera_module_pr_debug(
+ sd,
+ "could not get module %s from dts!\n",
+ OF_CAMERA_MODULE_MIPI_DPHY_INDEX);
+ }
+
+ of_node_put(np);
+ return pdata;
+err:
+ pltfrm_camera_module_pr_err(sd, "failed with error %d\n", ret);
+ if (!IS_ERR_OR_NULL(pdata->regulators.regulator)) {
+ devm_kfree(
+ &client->dev,
+ pdata->regulators.regulator);
+ pdata->regulators.regulator = NULL;
+ }
+
+ if (!IS_ERR_OR_NULL(pdata->mclk)) {
+ devm_clk_put(&client->dev, pdata->mclk);
+ pdata->mclk = NULL;
+ }
+ if (!IS_ERR_OR_NULL(pdata)) {
+ devm_kfree(&client->dev, pdata);
+ pdata = NULL;
+ }
+ of_node_put(np);
+ return ERR_PTR(ret);
+}
+
+static int pltfrm_camera_module_pix_frmt2code(
+ const char *pix_frmt)
+{
+ if (strcmp(pix_frmt, "BAYER_BGGR8") == 0)
+ return MEDIA_BUS_FMT_SBGGR8_1X8;
+ if (strcmp(pix_frmt, "BAYER_GBRG8") == 0)
+ return MEDIA_BUS_FMT_SGBRG8_1X8;
+ if (strcmp(pix_frmt, "BAYER_GRBG8") == 0)
+ return MEDIA_BUS_FMT_SGRBG8_1X8;
+ if (strcmp(pix_frmt, "BAYER_RGGB8") == 0)
+ return MEDIA_BUS_FMT_SRGGB8_1X8;
+ if (strcmp(pix_frmt, "BAYER_BGGR10") == 0)
+ return MEDIA_BUS_FMT_SBGGR10_1X10;
+ if (strcmp(pix_frmt, "BAYER_GBRG10") == 0)
+ return MEDIA_BUS_FMT_SGBRG10_1X10;
+ if (strcmp(pix_frmt, "BAYER_GRBG10") == 0)
+ return MEDIA_BUS_FMT_SGRBG10_1X10;
+ if (strcmp(pix_frmt, "BAYER_RGGB10") == 0)
+ return MEDIA_BUS_FMT_SRGGB10_1X10;
+ if (strcmp(pix_frmt, "BAYER_BGGR12") == 0)
+ return MEDIA_BUS_FMT_SBGGR12_1X12;
+ if (strcmp(pix_frmt, "BAYER_GBRG12") == 0)
+ return MEDIA_BUS_FMT_SGBRG12_1X12;
+ if (strcmp(pix_frmt, "BAYER_GRBG12") == 0)
+ return MEDIA_BUS_FMT_SGRBG12_1X12;
+ if (strcmp(pix_frmt, "BAYER_RGGB12") == 0)
+ return MEDIA_BUS_FMT_SRGGB12_1X12;
+ if (strcmp(pix_frmt, "YUYV8") == 0)
+ return MEDIA_BUS_FMT_YUYV8_2X8;
+ if (strcmp(pix_frmt, "YUYV10") == 0)
+ return MEDIA_BUS_FMT_YUYV10_2X10;
+ if (strcmp(pix_frmt, "UYUV8") == 0)
+ return MEDIA_BUS_FMT_UYVY8_2X8;
+ return -EINVAL;
+}
+
+static int pltfrm_camera_module_config_matches(
+ struct v4l2_subdev *sd,
+ struct device_node *config,
+ struct v4l2_mbus_framefmt *frm_fmt,
+ struct v4l2_subdev_frame_interval *frm_intrvl)
+{
+ int ret = 0;
+ struct property *prop;
+ const char *of_pix_fmt;
+ bool match = true;
+ u32 min, min2, max, max2;
+ u32 numerator, denominator;
+
+ pltfrm_camera_module_pr_debug(sd,
+ "pix_frm %d, %dx%d@%d/%dfps, config %s\n",
+ frm_fmt->code, frm_fmt->width, frm_fmt->height,
+ frm_intrvl->interval.denominator,
+ frm_intrvl->interval.numerator,
+ config->name);
+
+ /* check pixel format */
+ of_property_for_each_string(config, "rockchip,frm-pixel-format",
+ prop, of_pix_fmt) {
+ if (pltfrm_camera_module_pix_frmt2code(of_pix_fmt) ==
+ frm_fmt->code) {
+ match = true;
+ break;
+ }
+ }
+
+ if (!match)
+ return 0;
+
+ /* check frame width */
+ ret = of_property_read_u32(config, "rockchip,frm-width", &min);
+ if (ret == -EINVAL) {
+ ret = of_property_read_u32_index(config,
+ "rockchip,frm-width-range", 0, &min);
+ if (ret == -EINVAL) {
+ min = 0;
+ max = UINT_MAX;
+ } else if (IS_ERR_VALUE(ret)) {
+ pltfrm_camera_module_pr_err(sd,
+ "malformed property 'rockchip,frm-width-range'\n");
+ goto err;
+ } else {
+ ret = of_property_read_u32_index(config,
+ "rockchip,frm-width-range", 1, &max);
+ if (IS_ERR_VALUE(ret)) {
+ pltfrm_camera_module_pr_err(sd,
+ "malformed property 'rockchip,frm-width-range'\n");
+ goto err;
+ }
+ }
+ } else if (IS_ERR_VALUE(ret)) {
+ pltfrm_camera_module_pr_err(sd,
+ "malformed property 'rockchip,frm-width'\n");
+ goto err;
+ } else {
+ max = min;
+ }
+ if ((frm_fmt->width < min) || (frm_fmt->width > max))
+ return 0;
+
+ /* check frame height */
+ ret = of_property_read_u32(config, "rockchip,frm-height", &min);
+ if (ret == -EINVAL) {
+ ret = of_property_read_u32_index(config,
+ "rockchip,frm-height-range", 0, &min);
+ if (ret == -EINVAL) {
+ min = 0;
+ max = UINT_MAX;
+ } else if (IS_ERR_VALUE(ret)) {
+ pltfrm_camera_module_pr_err(sd,
+ "malformed property 'rockchip,frm-height-range'\n");
+ goto err;
+ } else {
+ ret = of_property_read_u32_index(config,
+ "rockchip,frm-height-range", 1, &max);
+ if (IS_ERR_VALUE(ret)) {
+ pltfrm_camera_module_pr_err(sd,
+ "malformed property 'rockchip,frm-height-range'\n");
+ goto err;
+ }
+ }
+ } else if (IS_ERR_VALUE(ret)) {
+ pltfrm_camera_module_pr_err(sd,
+ "malformed property 'rockchip,frm-height'\n");
+ goto err;
+ } else {
+ max = min;
+ }
+ if ((frm_fmt->height < min) || (frm_fmt->height > max))
+ return 0;
+
+ /* check frame interval */
+ ret = of_property_read_u32_index(config,
+ "rockchip,frm-interval", 0, &min);
+ if (ret == -EINVAL) {
+ ret = of_property_read_u32_index(config,
+ "rockchip,frm-interval-range", 0, &min);
+ if (ret == -EINVAL) {
+ min = 0;
+ max = UINT_MAX;
+ } else if (IS_ERR_VALUE(ret)) {
+ pltfrm_camera_module_pr_err(sd,
+ "malformed property 'rockchip,frm-interval-range'\n");
+ goto err;
+ } else {
+ ret |= of_property_read_u32_index(config,
+ "rockchip,frm-interval-range", 1, &min2);
+ ret |= of_property_read_u32_index(config,
+ "rockchip,frm-interval-range", 2, &max);
+ ret |= of_property_read_u32_index(config,
+ "rockchip,frm-interval-range", 3, &max2);
+ if (IS_ERR_VALUE(ret)) {
+ pltfrm_camera_module_pr_err(sd,
+ "malformed property 'rockchip,frm-interval-range'\n");
+ goto err;
+ }
+ }
+ } else if (IS_ERR_VALUE(ret)) {
+ pltfrm_camera_module_pr_err(sd,
+ "malformed property 'rockchip,frm-interval'\n");
+ goto err;
+ } else {
+ ret = of_property_read_u32_index(config,
+ "rockchip,frm-interval", 1, &min2);
+ if (IS_ERR_VALUE(ret)) {
+ pltfrm_camera_module_pr_err(sd,
+ "malformed property 'rockchip,frm-interval'\n");
+ goto err;
+ }
+ max = min;
+ max2 = min2;
+ }
+
+ /* normalize frame intervals */
+ denominator = lcm(min2, frm_intrvl->interval.denominator);
+ denominator = lcm(max2, denominator);
+ numerator = denominator / frm_intrvl->interval.denominator *
+ frm_intrvl->interval.numerator;
+
+ min = denominator / min2 * min;
+ max = denominator / max2 * max;
+
+ if ((numerator < min) || (numerator > max))
+ return 0;
+
+ return 1;
+err:
+ pltfrm_camera_module_pr_err(sd,
+ "failed with error %d\n", ret);
+ return ret;
+}
+
+static int pltfrm_camera_module_write_reglist_node(
+ struct v4l2_subdev *sd,
+ struct device_node *config_node)
+{
+ struct property *reg_table_prop;
+ struct pltfrm_camera_module_reg *reg_table = NULL;
+ u32 reg_table_num_entries;
+ u32 i = 0;
+ int ret = 0;
+
+ reg_table_prop = of_find_property(config_node, "rockchip,reg-table",
+ ®_table_num_entries);
+ if (!IS_ERR_OR_NULL(reg_table_prop)) {
+ if (((reg_table_num_entries / 12) == 0) ||
+ (reg_table_num_entries % 3)) {
+ pltfrm_camera_module_pr_err(sd,
+ "wrong register format in %s, must be 'type, address, value' per register\n",
+ config_node->name);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ reg_table_num_entries /= 12;
+ reg_table = (struct pltfrm_camera_module_reg *)
+ kmalloc(reg_table_num_entries *
+ sizeof(struct pltfrm_camera_module_reg),
+ GFP_KERNEL);
+ if (IS_ERR_OR_NULL(reg_table)) {
+ pltfrm_camera_module_pr_err(sd,
+ "memory allocation failed\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ pltfrm_camera_module_pr_debug(sd,
+ "patching config with %s (%d registers)\n",
+ config_node->name, reg_table_num_entries);
+ for (i = 0; i < reg_table_num_entries; i++) {
+ u32 val;
+
+ ret |= of_property_read_u32_index(
+ config_node, "rockchip,reg-table",
+ 3 * i, &val);
+ reg_table[i].flag = val;
+ ret |= of_property_read_u32_index(
+ config_node, "rockchip,reg-table",
+ 3 * i + 1, &val);
+ reg_table[i].reg = val;
+ ret |= of_property_read_u32_index(
+ config_node, "rockchip,reg-table",
+ 3 * i + 2, &val);
+ reg_table[i].val = val;
+ if (IS_ERR_VALUE(ret)) {
+ pltfrm_camera_module_pr_err(sd,
+ "error while reading property %s at index %d\n",
+ "rockchip,reg-table", i);
+ goto err;
+ }
+ }
+ ret = pltfrm_camera_module_write_reglist(
+ sd, reg_table, reg_table_num_entries);
+ if (IS_ERR_VALUE(ret))
+ goto err;
+ kfree(reg_table);
+ reg_table = NULL;
+ }
+ return 0;
+err:
+ pltfrm_camera_module_pr_err(sd,
+ "failed with error %d\n", ret);
+ kfree(reg_table);
+ return ret;
+}
+
+/* ======================================================================== */
+
+const char *pltfrm_dev_string(
+ struct v4l2_subdev *sd)
+{
+ struct i2c_client *client;
+
+ if (IS_ERR_OR_NULL(sd))
+ return "";
+ client = v4l2_get_subdevdata(sd);
+ if (IS_ERR_OR_NULL(client))
+ return "";
+ return dev_driver_string(&client->dev);
+}
+
+int pltfrm_camera_module_read_reg(
+ struct v4l2_subdev *sd,
+ u16 data_length,
+ u16 reg,
+ u32 *val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret = 0;
+ struct i2c_msg msg[1];
+ unsigned char data[4] = { 0, 0, 0, 0 };
+
+ if (!client->adapter) {
+ pltfrm_camera_module_pr_err(sd, "client->adapter NULL\n");
+ return -ENODEV;
+ }
+
+ msg->addr = client->addr;
+ msg->flags = I2C_M_WR;
+ msg->len = 2;
+ msg->buf = data;
+
+ /* High byte goes out first */
+ data[0] = (u8)(reg >> 8);
+ data[1] = (u8)(reg & 0xff);
+
+ ret = i2c_transfer(client->adapter, msg, 1);
+ if (ret >= 0) {
+ mdelay(3);
+ msg->flags = I2C_M_RD;
+ msg->len = data_length;
+ i2c_transfer(client->adapter, msg, 1);
+ }
+ if (ret >= 0) {
+ *val = 0;
+ /* High byte comes first */
+ if (data_length == 1)
+ *val = data[0];
+ else if (data_length == 2)
+ *val = data[1] + (data[0] << 8);
+ else
+ *val = data[3] + (data[2] << 8) +
+ (data[1] << 16) + (data[0] << 24);
+ return 0;
+ }
+ pltfrm_camera_module_pr_err(sd,
+ "i2c read from offset 0x%08x failed with error %d\n", reg, ret);
+ return ret;
+}
+
+/* ======================================================================== */
+
+int pltfrm_camera_module_write_reg(
+ struct v4l2_subdev *sd,
+ u16 reg, u8 val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret = 0;
+ struct i2c_msg msg[1];
+ unsigned char data[3];
+ int retries;
+
+ if (!client->adapter) {
+ pltfrm_camera_module_pr_err(sd, "client->adapter NULL\n");
+ return -ENODEV;
+ }
+
+ for (retries = 0; retries < 5; retries++) {
+ msg->addr = client->addr;
+ msg->flags = I2C_M_WR;
+ msg->len = 3;
+ msg->buf = data;
+
+ /* high byte goes out first */
+ data[0] = (u8)(reg >> 8);
+ data[1] = (u8)(reg & 0xff);
+ data[2] = val;
+
+ ret = i2c_transfer(client->adapter, msg, 1);
+ if (ret == 1) {
+ pltfrm_camera_module_pr_debug(sd,
+ "i2c write to offset 0x%08x success\n", reg);
+ return 0;
+ }
+
+ pltfrm_camera_module_pr_debug(sd,
+ "retrying I2C... %d\n", retries);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(msecs_to_jiffies(20));
+ }
+ pltfrm_camera_module_pr_err(sd,
+ "i2c write to offset 0x%08x failed with error %d\n", reg, ret);
+ return ret;
+}
+
+/* ======================================================================== */
+int pltfrm_camera_module_write_reglist(
+ struct v4l2_subdev *sd,
+ const struct pltfrm_camera_module_reg reglist[],
+ int len)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret = 0;
+ unsigned int k = 0, j = 0;
+ int i = 0;
+ struct i2c_msg *msg;
+ unsigned char *data;
+ unsigned int max_entries = len;
+
+ msg = kmalloc((sizeof(struct i2c_msg) * I2C_MSG_MAX),
+ GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+ data = kmalloc((sizeof(unsigned char) * I2C_DATA_MAX),
+ GFP_KERNEL);
+ if (!data) {
+ kfree(msg);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < max_entries; i++) {
+ switch (reglist[i].flag) {
+ case PLTFRM_CAMERA_MODULE_REG_TYPE_DATA:
+ (msg + j)->addr = client->addr;
+ (msg + j)->flags = I2C_M_WR;
+ (msg + j)->len = 3;
+ (msg + j)->buf = (data + k);
+
+ data[k + 0] = (u8)((reglist[i].reg & 0xFF00) >> 8);
+ data[k + 1] = (u8)(reglist[i].reg & 0xFF);
+ data[k + 2] = (u8)(reglist[i].val & 0xFF);
+ k = k + 3;
+ j++;
+ if (j == (I2C_MSG_MAX - 1)) {
+ /* Bulk I2C transfer */
+ pltfrm_camera_module_pr_debug(sd,
+ "messages transfers 1 0x%p msg %d bytes %d\n",
+ msg, j, k);
+ ret = i2c_transfer(client->adapter, msg, j);
+ if (ret < 0) {
+ pltfrm_camera_module_pr_err(sd,
+ "i2c transfer returned with err %d\n",
+ ret);
+ kfree(msg);
+ kfree(data);
+ return ret;
+ }
+ j = 0;
+ k = 0;
+ pltfrm_camera_module_pr_debug(sd,
+ "i2c_transfer return %d\n", ret);
+ }
+ break;
+ case PLTFRM_CAMERA_MODULE_REG_TYPE_TIMEOUT:
+ if (j > 0) {
+ /* Bulk I2C transfer */
+ pltfrm_camera_module_pr_debug(sd,
+ "messages transfers 1 0x%p msg %d bytes %d\n",
+ msg, j, k);
+ ret = i2c_transfer(client->adapter, msg, j);
+ if (ret < 0) {
+ pltfrm_camera_module_pr_debug(sd,
+ "i2c transfer returned with err %d\n",
+ ret);
+ kfree(msg);
+ kfree(data);
+ return ret;
+ }
+ pltfrm_camera_module_pr_debug(sd,
+ "i2c_transfer return %d\n", ret);
+ }
+ mdelay(reglist[i].val);
+ j = 0;
+ k = 0;
+ break;
+ default:
+ pltfrm_camera_module_pr_debug(sd, "unknown command\n");
+ kfree(msg);
+ kfree(data);
+ return -1;
+ }
+ }
+
+ if (j != 0) { /* Remaining I2C message */
+ pltfrm_camera_module_pr_debug(sd,
+ "messages transfers 1 0x%p msg %d bytes %d\n",
+ msg, j, k);
+ ret = i2c_transfer(client->adapter, msg, j);
+ if (ret < 0) {
+ pltfrm_camera_module_pr_err(sd,
+ "i2c transfer returned with err %d\n", ret);
+ kfree(msg);
+ kfree(data);
+ return ret;
+ }
+ pltfrm_camera_module_pr_debug(sd,
+ "i2c_transfer return %d\n", ret);
+ }
+
+ kfree(msg);
+ kfree(data);
+ return 0;
+}
+
+static int pltfrm_camera_module_init_pm(
+ struct v4l2_subdev *sd,
+ struct pltfrm_soc_cfg *soc_cfg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct pltfrm_camera_module_data *pdata =
+ dev_get_platdata(&client->dev);
+
+ pdata->soc_cfg = soc_cfg;
+ return 0;
+}
+
+int pltfrm_camera_module_set_pm_state(
+ struct v4l2_subdev *sd,
+ int on)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct pltfrm_camera_module_data *pdata =
+ dev_get_platdata(&client->dev);
+ struct pltfrm_soc_cfg *soc_cfg =
+ pdata->soc_cfg;
+ struct pltfrm_soc_mclk_para mclk_para;
+ struct pltfrm_soc_cfg_para cfg_para;
+ struct pltfrm_cam_itf itf_cfg;
+ unsigned int i;
+
+ if (on) {
+ if (IS_ERR_OR_NULL(soc_cfg)) {
+ pltfrm_camera_module_pr_err(sd,
+ "set_pm_state failed! soc_cfg is %p!\n",
+ soc_cfg);
+ return -EINVAL;
+ }
+
+ if (pdata->regulators.regulator) {
+ for (i = 0; i < pdata->regulators.cnt; i++) {
+ struct pltfrm_camera_module_regulator
+ *regulator;
+
+ regulator = pdata->regulators.regulator + i;
+ if (IS_ERR(regulator->regulator))
+ continue;
+ regulator_set_voltage(
+ regulator->regulator,
+ regulator->min_uV,
+ regulator->max_uV);
+ if (regulator_enable(regulator->regulator))
+ pltfrm_camera_module_pr_err(sd,
+ "regulator_enable failed!\n");
+ }
+ }
+
+ pltfrm_camera_module_set_pin_state(
+ sd,
+ PLTFRM_CAMERA_MODULE_PIN_PWR,
+ PLTFRM_CAMERA_MODULE_PIN_STATE_ACTIVE);
+
+ pltfrm_camera_module_set_pin_state(
+ sd,
+ PLTFRM_CAMERA_MODULE_PIN_RESET,
+ PLTFRM_CAMERA_MODULE_PIN_STATE_ACTIVE);
+ usleep_range(100, 300);
+ pltfrm_camera_module_set_pin_state(
+ sd,
+ PLTFRM_CAMERA_MODULE_PIN_RESET,
+ PLTFRM_CAMERA_MODULE_PIN_STATE_INACTIVE);
+
+ mclk_para.io_voltage = PLTFRM_IO_1V8;
+ mclk_para.drv_strength = PLTFRM_DRV_STRENGTH_2;
+ cfg_para.cmd = PLTFRM_MCLK_CFG;
+ cfg_para.cfg_para = (void *)&mclk_para;
+ soc_cfg->soc_cfg(&cfg_para);
+
+ if (v4l2_subdev_call(sd,
+ core,
+ ioctl,
+ PLTFRM_CIFCAM_G_ITF_CFG,
+ (void *)&itf_cfg) == 0) {
+ clk_set_rate(pdata->mclk, itf_cfg.mclk_hz);
+ } else {
+ pltfrm_camera_module_pr_err(sd,
+ "PLTFRM_CIFCAM_G_ITF_CFG failed, mclk set 24m default.\n");
+ clk_set_rate(pdata->mclk, 24000000);
+ }
+ clk_prepare_enable(pdata->mclk);
+ } else {
+ clk_disable_unprepare(pdata->mclk);
+
+ pltfrm_camera_module_set_pin_state(
+ sd,
+ PLTFRM_CAMERA_MODULE_PIN_PWR,
+ PLTFRM_CAMERA_MODULE_PIN_STATE_INACTIVE);
+
+ if (pdata->regulators.regulator) {
+ for (i = 0; i < pdata->regulators.cnt; i++) {
+ struct pltfrm_camera_module_regulator
+ *regulator;
+
+ regulator = pdata->regulators.regulator + i;
+ if (IS_ERR(regulator->regulator))
+ continue;
+ regulator_disable(regulator->regulator);
+ }
+ }
+ }
+
+ return 0;
+}
+
+int pltfrm_camera_module_set_pin_state(
+ struct v4l2_subdev *sd,
+ const char *pin,
+ enum pltfrm_camera_module_pin_state state)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct pltfrm_camera_module_data *pdata =
+ dev_get_platdata(&client->dev);
+ int gpio_val;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pdata->gpios); i++) {
+ if (pin == pdata->gpios[i].label) {
+ if (!gpio_is_valid(pdata->gpios[i].pltfrm_gpio))
+ return 0;
+ if (state == PLTFRM_CAMERA_MODULE_PIN_STATE_ACTIVE)
+ gpio_val = (pdata->gpios[i].active_low ==
+ OF_GPIO_ACTIVE_LOW) ? 0 : 1;
+ else
+ gpio_val = (pdata->gpios[i].active_low ==
+ OF_GPIO_ACTIVE_LOW) ? 1 : 0;
+ gpio_set_value(pdata->gpios[i].pltfrm_gpio, gpio_val);
+ pltfrm_camera_module_pr_debug(sd,
+ "set GPIO #%d ('%s') to %s\n",
+ pdata->gpios[i].pltfrm_gpio,
+ pdata->gpios[i].label,
+ gpio_val ? "HIGH" : "LOW");
+
+ return 0;
+ }
+ }
+
+ pltfrm_camera_module_pr_err(sd,
+ "unknown pin '%s'\n",
+ pin);
+ return -EINVAL;
+}
+
+int pltfrm_camera_module_get_pin_state(
+ struct v4l2_subdev *sd,
+ const char *pin)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct pltfrm_camera_module_data *pdata =
+ dev_get_platdata(&client->dev);
+ int gpio_val;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pdata->gpios); i++) {
+ if (pin == pdata->gpios[i].label) {
+ if (!gpio_is_valid(pdata->gpios[i].pltfrm_gpio))
+ return 0;
+ gpio_val = gpio_get_value(pdata->gpios[i].pltfrm_gpio);
+ pltfrm_camera_module_pr_debug(
+ sd,
+ "get GPIO #%d ('%s') is %s\n",
+ pdata->gpios[i].pltfrm_gpio,
+ pdata->gpios[i].label,
+ gpio_val ? "HIGH" : "LOW");
+
+ return gpio_val;
+ }
+ }
+
+ pltfrm_camera_module_pr_err(
+ sd,
+ "unknown pin '%s'\n",
+ pin);
+ return -EINVAL;
+}
+
+int pltfrm_camera_module_s_power(
+ struct v4l2_subdev *sd,
+ int on)
+{
+ int ret;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct pltfrm_camera_module_data *pdata =
+ dev_get_platdata(&client->dev);
+
+ pltfrm_camera_module_pr_debug(sd, "%s\n", on ? "on" : "off");
+
+ if (on) {
+ /* Enable clock and voltage to Secondary Camera Sensor */
+ ret = pltfrm_camera_module_set_pm_state(sd, on);
+ if (IS_ERR_VALUE(ret))
+ pltfrm_camera_module_pr_err(sd,
+ "set PM state failed (%d), could not power on camera\n",
+ ret);
+ else {
+ pltfrm_camera_module_pr_debug(sd,
+ "set PM state to %d successful, camera module is on\n",
+ on);
+ ret = pltfrm_camera_module_set_pinctrl_state(
+ sd, pdata->pins_default);
+ }
+ } else {
+ /* Disable clock and voltage to Secondary Camera Sensor */
+ ret = pltfrm_camera_module_set_pinctrl_state(
+ sd, pdata->pins_sleep);
+ if (!IS_ERR_VALUE(ret)) {
+ ret = pltfrm_camera_module_set_pm_state(
+ sd, on);
+ if (IS_ERR_VALUE(ret))
+ pltfrm_camera_module_pr_err(sd,
+ "set PM state failed (%d), could not power off camera\n",
+ ret);
+ else
+ pltfrm_camera_module_pr_debug(sd,
+ "set PM state to %d successful, camera module is off\n",
+ on);
+ }
+ }
+ return ret;
+}
+
+struct v4l2_subdev *pltfrm_camera_module_get_af_ctrl(
+ struct v4l2_subdev *sd)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct pltfrm_camera_module_data *pdata =
+ dev_get_platdata(&client->dev);
+
+ return pdata->af_ctrl;
+}
+
+char *pltfrm_camera_module_get_flash_driver_name(
+ struct v4l2_subdev *sd)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct pltfrm_camera_module_data *pdata =
+ dev_get_platdata(&client->dev);
+
+ return (char *)pdata->fl_ctrl.flash_driver_name;
+}
+
+struct v4l2_subdev *pltfrm_camera_module_get_fl_ctrl(
+ struct v4l2_subdev *sd)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct pltfrm_camera_module_data *pdata =
+ dev_get_platdata(&client->dev);
+
+ return pdata->fl_ctrl.flsh_ctrl;
+}
+
+int pltfrm_camera_module_patch_config(
+ struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *frm_fmt,
+ struct v4l2_subdev_frame_interval *frm_intrvl)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct device_node *parent_node = of_node_get(client->dev.of_node);
+ struct device_node *child_node = NULL, *prev_node = NULL;
+ int ret = 0;
+
+ pltfrm_camera_module_pr_debug(sd, "pix_fmt %d, %dx%d@%d/%dfps\n",
+ frm_fmt->code, frm_fmt->width, frm_fmt->height,
+ frm_intrvl->interval.denominator,
+ frm_intrvl->interval.numerator);
+
+ while (!IS_ERR_OR_NULL(child_node =
+ of_get_next_child(parent_node, prev_node))) {
+ if (strncasecmp(child_node->name,
+ "rockchip,camera-module-config",
+ strlen("rockchip,camera-module-config")) == 0) {
+ ret = pltfrm_camera_module_config_matches(
+ sd, child_node, frm_fmt, frm_intrvl);
+ if (IS_ERR_VALUE(ret))
+ goto err;
+ if (ret) {
+ ret =
+ pltfrm_camera_module_write_reglist_node(
+ sd, child_node);
+ if (!IS_ERR_VALUE(ret))
+ goto err;
+ }
+ }
+ of_node_put(prev_node);
+ prev_node = child_node;
+ }
+ of_node_put(prev_node);
+ of_node_put(parent_node);
+
+ return 0;
+err:
+ pltfrm_camera_module_pr_err(sd,
+ "failed with error %d\n", ret);
+ of_node_put(prev_node);
+ of_node_put(child_node);
+ of_node_put(parent_node);
+ return ret;
+}
+
+int pltfrm_camera_module_init(
+ struct v4l2_subdev *sd,
+ void **pldata)
+{
+ int ret = 0;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct pltfrm_camera_module_data *pdata;
+
+ pltfrm_camera_module_pr_debug(sd, "\n");
+
+ pdata = pltfrm_camera_module_get_data(sd);
+ if (IS_ERR_OR_NULL(pdata)) {
+ pltfrm_camera_module_pr_err(sd,
+ "unable to get platform data\n");
+ return -EFAULT;
+ }
+
+ ret = pltfrm_camera_module_init_gpio(sd);
+ if (IS_ERR_VALUE(ret)) {
+ pltfrm_camera_module_pr_err(sd,
+ "GPIO initialization failed (%d)\n", ret);
+ }
+
+ if (IS_ERR_VALUE(ret))
+ devm_kfree(&client->dev, pdata);
+ else
+ *(struct pltfrm_camera_module_data **)pldata = pdata;
+
+ return ret;
+}
+
+void pltfrm_camera_module_release(
+ struct v4l2_subdev *sd)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct pltfrm_camera_module_data *pdata =
+ dev_get_platdata(&client->dev);
+ int i;
+
+ /* GPIOs also needs to be freed for other sensors to use */
+ for (i = 0; i < ARRAY_SIZE(pdata->gpios); i++) {
+ if (gpio_is_valid(pdata->gpios[i].pltfrm_gpio)) {
+ pltfrm_camera_module_pr_debug(sd,
+ "free GPIO #%d ('%s')\n",
+ pdata->gpios[i].pltfrm_gpio,
+ pdata->gpios[i].label);
+ gpio_free(
+ pdata->gpios[i].pltfrm_gpio);
+ }
+ }
+ for (i = 0; i < pdata->regulators.cnt; i++) {
+ if (!IS_ERR(pdata->regulators.regulator[i].regulator))
+ devm_regulator_put(
+ pdata->regulators.regulator[i].regulator);
+ }
+ if (pdata->pinctrl)
+ devm_pinctrl_put(pdata->pinctrl);
+}
+
+/* ======================================================================== */
+long pltfrm_camera_module_ioctl(struct v4l2_subdev *sd,
+ unsigned int cmd,
+ void *arg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct pltfrm_camera_module_data *pdata =
+ dev_get_platdata(&client->dev);
+ int ret = 0;
+
+ pltfrm_camera_module_pr_debug(sd, "cmd: 0x%x\n", cmd);
+
+ if (cmd == RK_VIDIOC_CAMERA_MODULEINFO) {
+ struct camera_module_info_s *p_camera_module =
+ (struct camera_module_info_s *)arg;
+
+ /*
+ * strlcpy((char *)p_camera_module->sensor_name,
+ * (char *)client->driver->driver.name,
+ * sizeof(p_camera_module->sensor_name));
+ */
+
+ if (pdata->info.module_name)
+ strcpy((char *)p_camera_module->module_name,
+ pdata->info.module_name);
+ else
+ strcpy((char *)p_camera_module->module_name, "(null)");
+ if (pdata->info.len_name)
+ strcpy((char *)p_camera_module->len_name,
+ pdata->info.len_name);
+ else
+ strcpy((char *)p_camera_module->len_name, "(null)");
+ if (pdata->info.fov_h)
+ strcpy((char *)p_camera_module->fov_h,
+ pdata->info.fov_h);
+ else
+ strcpy((char *)p_camera_module->fov_h, "(null)");
+ if (pdata->info.fov_v)
+ strcpy((char *)p_camera_module->fov_v,
+ pdata->info.fov_v);
+ else
+ strcpy((char *)p_camera_module->fov_v, "(null)");
+ if (pdata->info.focal_length)
+ strcpy((char *)p_camera_module->focal_length,
+ pdata->info.focal_length);
+ else
+ strcpy((char *)p_camera_module->focal_length, "(null)");
+ if (pdata->info.focus_distance)
+ strcpy((char *)p_camera_module->focus_distance,
+ pdata->info.focus_distance);
+ else
+ strcpy((char *)p_camera_module->focus_distance,
+ "(null)");
+
+ p_camera_module->facing = pdata->info.facing;
+ p_camera_module->orientation = pdata->info.orientation;
+ p_camera_module->iq_mirror = pdata->info.iq_mirror;
+ p_camera_module->iq_flip = pdata->info.iq_flip;
+ p_camera_module->flash_support = pdata->info.flash_support;
+ p_camera_module->flash_exp_percent =
+ pdata->info.flash_exp_percent;
+
+ return 0;
+ } else if (cmd == PLTFRM_CIFCAM_G_DEFRECT) {
+ struct pltfrm_cam_defrect *defrect =
+ (struct pltfrm_cam_defrect *)arg;
+ unsigned int i;
+
+ for (i = 0; i < 4; i++) {
+ if ((pdata->defrects[i].width == defrect->width) &&
+ (pdata->defrects[i].height == defrect->height))
+ defrect->defrect = pdata->defrects[i].defrect;
+ }
+ return 0;
+ } else if (cmd == PLTFRM_CIFCAM_G_ITF_CFG) {
+ struct pltfrm_cam_itf *itf_cfg = (struct pltfrm_cam_itf *)arg;
+
+ if (PLTFRM_CAM_ITF_IS_MIPI(itf_cfg->type))
+ itf_cfg->cfg.mipi.dphy_index =
+ pdata->itf.itf.mipi.dphy_index;
+
+ return 0;
+ } else if (cmd == PLTFRM_CIFCAM_ATTACH) {
+ return pltfrm_camera_module_init_pm(sd,
+ (struct pltfrm_soc_cfg *)arg);
+ }
+
+ return ret;
+}
+
+int pltfrm_camera_module_get_flip_mirror(
+ struct v4l2_subdev *sd)
+{
+ int mode = 0;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct pltfrm_camera_module_data *pdata =
+ dev_get_platdata(&client->dev);
+
+ if ((pdata->info.flip == -1) && pdata->info.mirror == -1)
+ return -1;
+
+ if (pdata->info.flip)
+ mode |= 0x02;
+ else
+ mode &= ~0x02;
+
+ if (pdata->info.mirror)
+ mode |= 0x01;
+ else
+ mode &= ~0x01;
+
+ return mode;
+}
+#endif
+
--- /dev/null
+/*
+ * rk_camera_module.h
+ * (Based on Intel driver for sofiaxxx)
+ *
+ * Copyright (C) 2015 Intel Mobile Communications GmbH
+ * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#ifndef _RK_CAMERA_MODULE_VERSION_H_
+#define _RK_CAMERA_MODULE_VERSION_H_
+#include <linux/version.h>
+
+/*
+ * CIF DRIVER VERSION NOTE
+ *
+ * v0.1.0:
+ * 1. Initialize version;
+ * 2. Update sensor configuration after power up sensor in
+ * ov_camera_module_s_power.
+ * Because mipi datalane may be no still on LP11 state when
+ * sensor configuration;
+ *
+ */
+
+#define CONFIG_RK_CAMERA_MODULE_VERSION KERNEL_VERSION(0, 1, 0)
+
+#endif