--- /dev/null
+/*
+ * Support for OmniVision mt9e013 1080p HD camera sensor.
+ *
+ * Copyright (c) 2011 Intel Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kmod.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/moduleparam.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/bitops.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-i2c-drv.h>
+
+#include "mt9e013.h"
+
+#define to_mt9e013_sensor(sd) container_of(sd, struct mt9e013_device, sd)
+
+#define HOME_POS 255
+
+
+/* divides a by b using half up rounding and div/0 prevention
+ * (result is 0 if b == 0) */
+#define divsave_rounded(a, b) (((b) != 0) ? (((a)+((b)>>1))/(b)) : (-1))
+
+typedef unsigned int sensor_register;
+struct sensor_mode_data {
+ sensor_register coarse_integration_time_min;
+ sensor_register coarse_integration_time_max_margin;
+ sensor_register fine_integration_time_min;
+ sensor_register fine_integration_time_max_margin;
+ sensor_register fine_integration_time_def;
+ sensor_register frame_length_lines;
+ sensor_register line_length_pck;
+ sensor_register read_mode;
+ int vt_pix_clk_freq_mhz;
+};
+
+/*
+ * TODO: use debug parameter to actually define when debug messages should
+ * be printed.
+ */
+static int debug;
+static u16 real_model_id;
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable debug messages");
+
+struct mt9e013_resolution mt9e013_res_preview[] = {
+ {
+ .desc = "PREVIEW_30fps" ,
+ .width = 820 ,
+ .height = 616 ,
+ .fps = 30 ,
+ .used = 0 ,
+ .regs = mt9e013_PREVIEW_30fps ,
+ },
+ {
+ .desc = "WIDE_PREVIEW_30fps" ,
+ .width = 1640 ,
+ .height = 956 ,
+ .fps = 30 ,
+ .used = 0 ,
+ .regs = mt9e013_WIDE_PREVIEW_30fps ,
+ },
+
+};
+
+#define N_RES_PREVIEW (ARRAY_SIZE(mt9e013_res_preview))
+
+struct mt9e013_resolution mt9e013_res_still[] = {
+ {
+ .desc = "STILL_2M_15fps" ,
+ .width = 1640 ,
+ .height = 1232 ,
+ .fps = 15 ,
+ .used = 0 ,
+ .regs = mt9e013_STILL_2M_15fps ,
+ },
+ {
+ .desc = "STILL_6M_15fps" ,
+ .width = 3280 ,
+ .height = 1848 ,
+ .fps = 15 ,
+ .used = 0 ,
+ .regs = mt9e013_STILL_6M_15fps ,
+ },
+ {
+ .desc = "STILL_8M_12fps" ,
+ .width = 3280 ,
+ .height = 2464 ,
+ .fps = 12 ,
+ .used = 0 ,
+ .regs = mt9e013_STILL_8M_12fps ,
+ },
+};
+
+#define N_RES_STILL (ARRAY_SIZE(mt9e013_res_still))
+
+struct mt9e013_resolution mt9e013_res_video[] = {
+ {
+ .desc = "QCIF_strong_dvs_30fps" ,
+ .width = 384 ,
+ .height = 292 ,
+ .fps = 30 ,
+ .used = 0 ,
+ .regs = mt9e013_QCIF_strong_dvs_30fps ,
+ },
+ {
+ .desc = "QVGA_strong_dvs_30fps" ,
+ .width = 384 ,
+ .height = 288 ,
+ .fps = 30 ,
+ .used = 0 ,
+ .regs = mt9e013_QVGA_strong_dvs_30fps ,
+ },
+ {
+ .desc = "VGA_strong_dvs_30fps" ,
+ .width = 820 ,
+ .height = 616 ,
+ .fps = 30 ,
+ .used = 0 ,
+ .regs = mt9e013_VGA_strong_dvs_30fps ,
+ },
+ {
+ .desc = "WVGA_strong_dvs_30fps" ,
+ .width = 1640 ,
+ .height = 1024 ,
+ .fps = 30 ,
+ .used = 0 ,
+ .regs = mt9e013_WVGA_strong_dvs_30fps ,
+ },
+ {
+ .desc = "720p_strong_dvs_30fps" ,
+ .width = 1568 ,
+ .height = 876 ,
+ .fps = 30 ,
+ .used = 0 ,
+ .regs = mt9e013_720p_strong_dvs_30fps ,
+ },
+ {
+ .desc = "1080p_strong_dvs_30fps",
+ .width = 2336,
+ .height = 1308,
+ .fps = 30,
+ .used = 0,
+ .regs = mt9e013_1080p_strong_dvs_30fps,
+ },
+};
+
+#define N_RES_VIDEO (ARRAY_SIZE(mt9e013_res_video))
+
+struct mt9e013_resolution *mt9e013_res = mt9e013_res_preview;
+static int N_RES = N_RES_PREVIEW;
+
+static int
+mt9e013_read_reg(struct i2c_client *client, u16 len, u16 reg, u16 *val)
+{
+ struct i2c_msg msg[2];
+ u16 data[MT9E013_SHORT_MAX];
+ int err, i;
+
+ if (!client->adapter) {
+ v4l2_err(client, "%s error, no client->adapter\n", __func__);
+ return -ENODEV;
+ }
+
+ /* @len should be even when > 1 */
+ if (len > MT9E013_BYTE_MAX) {
+ v4l2_err(client, "%s error, invalid data length\n", __func__);
+ return -EINVAL;
+ }
+
+ memset(msg, 0 , sizeof(msg));
+
+ msg[0].addr = client->addr;
+ msg[0].flags = 0;
+ msg[0].len = I2C_MSG_LENGTH;
+ msg[0].buf = (u8 *)data;
+ /* high byte goes first */
+ data[0] = cpu_to_be16(reg);
+
+ msg[1].addr = client->addr;
+ msg[1].len = len;
+ msg[1].flags = I2C_M_RD;
+ msg[1].buf = (u8 *)data;
+
+ err = i2c_transfer(client->adapter, msg, 2);
+ if (err < 0)
+ goto error;
+
+ /* high byte comes first */
+ if (len == MT9E013_8BIT) {
+ *val = (u8)data[0];
+ } else {
+ /* 16-bit access is default when len > 1 */
+ for (i = 0; i < (len >> 1); i++)
+ val[i] = be16_to_cpu(data[i]);
+ }
+
+ return 0;
+
+error:
+ dev_err(&client->dev, "read from offset 0x%x error %d", reg, err);
+ return err;
+}
+
+static int mt9e013_i2c_write(struct i2c_client *client, u16 len, u8 *data)
+{
+ struct i2c_msg msg;
+ const int num_msg = 1;
+ int ret;
+ int retry = 0;
+
+again:
+ msg.addr = client->addr;
+ msg.flags = 0;
+ msg.len = len;
+ msg.buf = data;
+
+ ret = i2c_transfer(client->adapter, &msg, 1);
+
+ /*
+ * It is said that Rev 2 sensor needs some delay here otherwise
+ * registers do not seem to load correctly. But tests show that
+ * removing the delay would not cause any in-stablility issue and the
+ * delay will cause serious performance down, so, removed previous
+ * mdelay(1) here.
+ */
+
+ if (ret == num_msg)
+ return 0;
+
+ if (retry <= I2C_RETRY_COUNT) {
+ dev_err(&client->dev, "retrying i2c write transfer... %d",
+ retry);
+ retry++;
+ msleep(20);
+ goto again;
+ }
+
+ return ret;
+}
+
+static int
+mt9e013_write_reg(struct i2c_client *client, u16 data_length, u16 reg, u16 val)
+{
+ int ret;
+ unsigned char data[4] = {0};
+ u16 *wreg;
+ const u16 len = data_length + sizeof(u16); /* 16-bit address + data */
+
+ if (!client->adapter) {
+ v4l2_err(client, "%s error, no client->adapter\n", __func__);
+ return -ENODEV;
+ }
+
+ if (data_length != MT9E013_8BIT && data_length != MT9E013_16BIT) {
+ v4l2_err(client, "%s error, invalid data_length\n", __func__);
+ return -EINVAL;
+ }
+
+ /* high byte goes out first */
+ wreg = (u16 *)data;
+ *wreg = cpu_to_be16(reg);
+
+ if (data_length == MT9E013_8BIT) {
+ data[2] = (u8)(val);
+ } else {
+ /* MT9E013_16BIT */
+ u16 *wdata = (u16 *)&data[2];
+ *wdata = be16_to_cpu(val);
+ }
+
+ ret = mt9e013_i2c_write(client, len, data);
+ if (ret)
+ dev_err(&client->dev,
+ "write error: wrote 0x%x to offset 0x%x error %d",
+ val, reg, ret);
+
+ return ret;
+}
+
+
+/**
+ * mt9e013_rmw_reg - Read/Modify/Write a value to a register in the sensor
+ * device
+ * @client: i2c driver client structure
+ * @data_length: 8/16-bits length
+ * @reg: register address
+ * @mask: masked out bits
+ * @set: bits set
+ *
+ * Read/modify/write a value to a register in the sensor device.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int mt9e013_rmw_reg(struct i2c_client *client, u16 data_length, u16 reg,
+ u16 mask, u16 set)
+{
+ int err;
+ u16 val;
+
+ /* Exit when no mask */
+ if (mask == 0)
+ return 0;
+
+ /* @mask must not exceed data length */
+ if (data_length == MT9E013_8BIT && mask & ~0xff)
+ return -EINVAL;
+
+ err = mt9e013_read_reg(client, data_length, reg, &val);
+ if (err) {
+ v4l2_err(client, "mt9e013_rmw_reg error exit, read failed\n");
+ return -EINVAL;
+ }
+
+ val &= ~mask;
+
+ /*
+ * Perform the OR function if the @set exists.
+ * Shift @set value to target bit location. @set should set only
+ * bits included in @mask.
+ *
+ * REVISIT: This function expects @set to be non-shifted. Its shift
+ * value is then defined to be equal to mask's LSB position.
+ * How about to inform values in their right offset position and avoid
+ * this unneeded shift operation?
+ */
+ set <<= ffs(mask) - 1;
+ val |= set & mask;
+
+ err = mt9e013_write_reg(client, data_length, reg, val);
+ if (err) {
+ v4l2_err(client, "mt9e013_rmw_reg error exit, write failed\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
+/*
+ * mt9e013_write_reg_array - Initializes a list of MT9M114 registers
+ * @client: i2c driver client structure
+ * @reglist: list of registers to be written
+ *
+ * This function initializes a list of registers. When consecutive addresses
+ * are found in a row on the list, this function creates a buffer and sends
+ * consecutive data in a single i2c_transfer().
+ *
+ * __mt9e013_flush_reg_array, __mt9e013_buf_reg_array() and
+ * __mt9e013_write_reg_is_consecutive() are internal functions to
+ * mt9e013_write_reg_array_fast() and should be not used anywhere else.
+ *
+ */
+
+static int __mt9e013_flush_reg_array(struct i2c_client *client,
+ struct mt9e013_write_ctrl *ctrl)
+{
+ u16 size;
+
+ if (ctrl->index == 0)
+ return 0;
+
+ size = sizeof(u16) + ctrl->index; /* 16-bit address + data */
+ ctrl->buffer.addr = cpu_to_be16(ctrl->buffer.addr);
+ ctrl->index = 0;
+
+ return mt9e013_i2c_write(client, size, (u8 *)&ctrl->buffer);
+}
+
+static int __mt9e013_buf_reg_array(struct i2c_client *client,
+ struct mt9e013_write_ctrl *ctrl,
+ const struct mt9e013_reg *next)
+{
+ int size;
+ u16 *data16;
+
+ switch (next->type) {
+ case MT9E013_8BIT:
+ size = 1;
+ ctrl->buffer.data[ctrl->index] = (u8)next->val;
+ break;
+ case MT9E013_16BIT:
+ size = 2;
+ data16 = (u16 *)&ctrl->buffer.data[ctrl->index];
+ *data16 = cpu_to_be16((u16)next->val);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* When first item is added, we need to store its starting address */
+ if (ctrl->index == 0)
+ ctrl->buffer.addr = next->reg.sreg;
+
+ ctrl->index += size;
+
+ /*
+ * Buffer cannot guarantee free space for u32? Better flush it to avoid
+ * possible lack of memory for next item.
+ */
+ if (ctrl->index + sizeof(u16) >= MT9E013_MAX_WRITE_BUF_SIZE)
+ __mt9e013_flush_reg_array(client, ctrl);
+
+ return 0;
+}
+
+static int
+__mt9e013_write_reg_is_consecutive(struct i2c_client *client,
+ struct mt9e013_write_ctrl *ctrl,
+ const struct mt9e013_reg *next)
+{
+ if (ctrl->index == 0)
+ return 1;
+
+ return ctrl->buffer.addr + ctrl->index == next->reg.sreg;
+}
+
+static int mt9e013_write_reg_array(struct i2c_client *client,
+ const struct mt9e013_reg *reglist)
+{
+ const struct mt9e013_reg *next = reglist;
+ struct mt9e013_write_ctrl ctrl;
+ int err;
+
+ ctrl.index = 0;
+ for (; next->type != MT9E013_TOK_TERM; next++) {
+ switch (next->type & MT9E013_TOK_MASK) {
+ case MT9E013_TOK_DELAY:
+ err = __mt9e013_flush_reg_array(client, &ctrl);
+ if (err)
+ return err;
+ msleep(next->val);
+ break;
+
+ case MT9E013_RMW:
+ err = __mt9e013_flush_reg_array(client, &ctrl);
+ err |= mt9e013_rmw_reg(client,
+ next->type & ~MT9E013_RMW,
+ next->reg.sreg, next->val,
+ next->val2);
+ if (err) {
+ v4l2_err(client, "%s: rwm error, "
+ "aborted\n", __func__);
+ return err;
+ }
+ break;
+
+ default:
+ /*
+ * If next address is not consecutive, data needs to be
+ * flushed before proceed.
+ */
+ if (!__mt9e013_write_reg_is_consecutive(client, &ctrl,
+ next)) {
+ err = __mt9e013_flush_reg_array(client, &ctrl);
+ if (err)
+ return err;
+ }
+ err = __mt9e013_buf_reg_array(client, &ctrl, next);
+ if (err) {
+ v4l2_err(client, "%s: write error, aborted\n",
+ __func__);
+ return err;
+ }
+ break;
+ }
+ }
+
+ return __mt9e013_flush_reg_array(client, &ctrl);
+}
+
+
+static int mt9e013_t_focus_abs(struct v4l2_subdev *sd, s32 value)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9e013_device *dev = to_mt9e013_sensor(sd);
+ int ret;
+
+ value = min(value, MT9E013_MAX_FOCUS_POS);
+
+ ret = mt9e013_write_reg(client, MT9E013_16BIT, MT9E013_VCM_CODE,
+ MT9E013_MAX_FOCUS_POS - value);
+ if (ret == 0) {
+ dev->focus = value;
+ do_gettimeofday(&(dev->timestamp_t_focus_abs));
+ }
+ return ret;
+}
+
+static int mt9e013_q_focus_abs(struct v4l2_subdev *sd, s32 *value)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+ u16 val;
+
+
+
+ ret = mt9e013_read_reg(client, MT9E013_16BIT,
+ MT9E013_VCM_CODE, &val);
+ *value = MT9E013_MAX_FOCUS_POS - val;
+
+ return ret;
+}
+
+static int mt9e013_t_focus_rel(struct v4l2_subdev *sd, s32 value)
+{
+ struct mt9e013_device *dev = to_mt9e013_sensor(sd);
+ return mt9e013_t_focus_abs(sd, dev->focus + value);
+}
+
+#define WAIT_FOR_VCM_MOTOR 60000
+static int mt9e013_q_focus_status(struct v4l2_subdev *sd, s32 *value)
+{
+ u32 status = 0;
+ struct mt9e013_device *dev = to_mt9e013_sensor(sd);
+ struct timeval current_time;
+ bool stillmoving = false;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+
+ do_gettimeofday(¤t_time);
+ if (current_time.tv_sec == (dev->timestamp_t_focus_abs).tv_sec) {
+ if (current_time.tv_usec < ((dev->timestamp_t_focus_abs).tv_usec+WAIT_FOR_VCM_MOTOR)) {
+ stillmoving = true;
+ }
+ } else {
+ if ((current_time.tv_usec+1000000) < ((dev->timestamp_t_focus_abs).tv_usec+WAIT_FOR_VCM_MOTOR)) {
+ /* assuming the delay betwee calls does not take more than a second. */
+ stillmoving = true;
+ }
+ }
+
+ if (stillmoving) {
+ status |= ATOMISP_FOCUS_STATUS_MOVING;
+ status |= ATOMISP_FOCUS_HP_IN_PROGRESS;
+ } else {
+ status |= ATOMISP_FOCUS_HP_COMPLETE;
+ status |= ATOMISP_FOCUS_STATUS_ACCEPTS_NEW_MOVE;
+ }
+ *value = status;
+ return 0;
+}
+
+/*
+static int mt9e013_vcm_enable(struct v4l2_subdev *sd)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ return mt9e013_rmw_reg(client, MT9E013_16BIT, MT9E013_VCM_SLEW_STEP,
+ MT9E013_VCM_ENABLE, 0x1);
+}
+*/
+static long mt9e013_set_exposure(struct v4l2_subdev *sd, u16 coarse_itg,
+ u16 fine_itg, u16 gain)
+
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+ u16 frame_length;
+ struct mt9e013_device *dev = to_mt9e013_sensor(sd);
+
+ if (mt9e013_read_reg(client, MT9E013_16BIT,
+ MT9E013_FRAME_LENGTH_LINES, &frame_length))
+ return -EINVAL;
+
+ /* enable group hold */
+ ret = mt9e013_write_reg_array(client, mt9e013_param_hold);
+ if (ret)
+ return ret;
+
+ /* set coarse integration time */
+ ret = mt9e013_write_reg(client, MT9E013_16BIT,
+ MT9E013_COARSE_INTEGRATION_TIME, coarse_itg);
+ if (ret)
+ goto error;
+
+ /* set fine integration time */
+ ret = mt9e013_write_reg(client, MT9E013_16BIT,
+ MT9E013_FINE_INTEGRATION_TIME, fine_itg);
+ if (ret)
+ goto error;
+
+ /* set global gain */
+ ret = mt9e013_write_reg(client, MT9E013_16BIT,
+ MT9E013_GLOBAL_GAIN, gain);
+
+ if (ret)
+ goto error;
+ dev->gain = gain;
+ dev->coarse_itg = coarse_itg;
+ dev->fine_itg = fine_itg;
+
+error:
+ /* disable group hold */
+ mt9e013_write_reg_array(client, mt9e013_param_update);
+ return ret;
+}
+
+static long mt9e013_s_exposure(struct v4l2_subdev *sd,
+ struct atomisp_exposure *exposure)
+{
+ u16 coarse_itg, fine_itg, gain;
+
+ coarse_itg = exposure->integration_time[0];
+ fine_itg = exposure->integration_time[1];
+ gain = exposure->gain[0];
+
+ return mt9e013_set_exposure(sd, coarse_itg, fine_itg, gain);
+}
+
+static int mt9e013_read_reg_array(struct i2c_client *client, u16 size, u16 addr,
+ void *data)
+{
+ u8 *buf = data;
+ u16 index;
+ int ret = 0;
+
+ for (index = 0; index + MT9E013_BYTE_MAX <= size;
+ index += MT9E013_BYTE_MAX) {
+ ret = mt9e013_read_reg(client, MT9E013_BYTE_MAX,
+ MT9E013_OTP_START_ADDR + index,
+ (u16 *)&buf[index]);
+ if (ret)
+ return ret;
+ }
+
+ if (size - index > 0)
+ ret = mt9e013_read_reg(client, size - index,
+ MT9E013_OTP_START_ADDR + index,
+ (u16 *)&buf[index]);
+
+ return ret;
+}
+
+static unsigned long
+mt9e013_otp_sum(struct v4l2_subdev *sd, u8 *buf, u16 start, u16 end)
+{
+ unsigned long sum = 0;
+ u16 i;
+
+ for (i = start; i <= end; i++)
+ sum += buf[i];
+
+ return sum;
+}
+
+static int mt9e013_otp_checksum(struct v4l2_subdev *sd, u8 *buf, int list_len,
+ const struct mt9e013_otp_checksum_format *list)
+{
+ unsigned long sum;
+ u8 checksum;
+ int i;
+
+ for (i = 0; i < list_len; i++) {
+ sum = mt9e013_otp_sum(sd, buf, list[i].start, list[i].end);
+ checksum = sum % MT9E013_OTP_MOD_CHECKSUM;
+ if (buf[list[i].checksum] != checksum)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mt9e013_otp_read(struct v4l2_subdev *sd,
+ const struct mt9e013_reg *type,
+ void __user *data, u32 size)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+ int retry = 100;
+ void *buf;
+ u16 ready;
+
+ ret = mt9e013_write_reg_array(client, type);
+ if (ret) {
+ v4l2_err(client, "%s: failed to prepare OTP memory\n",
+ __func__);
+ return ret;
+ }
+
+ /*
+ * As we need to wait for sensor to prepare OTP memory, let's allocate
+ * buffer now to optimize time.
+ */
+ buf = kmalloc(MT9E013_OTP_DATA_SIZE, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ do {
+ ret = mt9e013_read_reg(client, MT9E013_16BIT,
+ MT9E013_OTP_READY_REG, &ready);
+ if (ret) {
+ v4l2_err(client, "%s: failed to read OTP memory "
+ "status\n", __func__);
+ goto out;
+ }
+ if (ready & MT9E013_OTP_READY_REG_DONE)
+ break;
+ } while (--retry);
+
+ if (!(ready & MT9E013_OTP_READY_REG_OK)) {
+ v4l2_info(client, "%s: OTP memory was initialized with error\n",
+ __func__);
+ goto out;
+ }
+ ret = mt9e013_read_reg_array(client, MT9E013_OTP_DATA_SIZE,
+ MT9E013_OTP_START_ADDR, buf);
+ if (ret) {
+ v4l2_err(client, "%s: failed to read OTP data\n", __func__);
+ goto out;
+ }
+ if (MT9E013_OTP_CHECKSUM) {
+ ret = mt9e013_otp_checksum(sd, buf,
+ ARRAY_SIZE(mt9e013_otp_checksum_list),
+ mt9e013_otp_checksum_list);
+ if (ret)
+ goto out;
+ }
+ ret = copy_to_user(data, buf, size);
+ if (ret)
+ v4l2_err(client, "%s: failed to copy OTP data to user\n",
+ __func__);
+
+out:
+ kfree(buf);
+ return ret;
+}
+
+static int mt9e013_g_priv_int_data(struct v4l2_subdev *sd,
+ struct v4l2_private_int_data *priv)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9e013_device *dev = to_mt9e013_sensor(sd);
+ u32 read_size = priv->size;
+ int ret;
+
+ if (!dev->power)
+ return -EIO;
+
+ if (dev->streaming)
+ return -EBUSY;
+
+ if (!priv)
+ return -EINVAL;
+
+ /* Return correct size */
+ priv->size = MT9E013_OTP_DATA_SIZE;
+
+ /* No need to copy data if size is 0 */
+ if (!read_size)
+ return 0;
+
+ /* Correct read_size value only if bigger than maximum */
+ if (read_size > MT9E013_OTP_DATA_SIZE)
+ read_size = MT9E013_OTP_DATA_SIZE;
+
+ /* Try all banks, one by one, and return after first success */
+ ret = mt9e013_otp_read(sd, mt9e013_otp_type30, priv->data, read_size);
+ if (!ret)
+ return 0;
+ ret = mt9e013_otp_read(sd, mt9e013_otp_type31, priv->data, read_size);
+ if (!ret)
+ return 0;
+ ret = mt9e013_otp_read(sd, mt9e013_otp_type32, priv->data, read_size);
+ if (!ret)
+ return 0;
+
+ /* Driver has failed to find valid data */
+ v4l2_info(client, "%s: sensor found no valid OTP data\n", __func__);
+ return ret;
+}
+
+static long mt9e013_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+ switch (cmd) {
+ case ATOMISP_IOC_S_EXPOSURE:
+ return mt9e013_s_exposure(sd, (struct atomisp_exposure *)arg);
+ case ATOMISP_IOC_G_SENSOR_PRIV_INT_DATA:
+ return mt9e013_g_priv_int_data(sd, arg);
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int mt9e013_init_registers(struct v4l2_subdev *sd)
+{
+ int ret;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ ret = mt9e013_write_reg_array(client, mt9e013_reset_register);
+ ret |= mt9e013_write_reg_array(client, mt9e013_pll_timing);
+ ret |= mt9e013_write_reg_array(client, mt9e013_raw_10);
+ ret |= mt9e013_write_reg_array(client, mt9e013_mipi_config);
+ ret |= mt9e013_write_reg_array(client, mt9e013_recommended_settings);
+ ret |= mt9e013_write_reg_array(client, mt9e013_mipi_timing);
+ ret |= mt9e013_write_reg_array(client, mt9e013_scaler);
+ ret |= mt9e013_write_reg_array(client, mt9e013_init_vcm);
+
+ return ret;
+}
+
+static int mt9e013_init(struct v4l2_subdev *sd, u32 val)
+{
+ int ret;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ /* set inital registers */
+ ret = mt9e013_init_registers(sd);
+
+ /*set VCM to home position */
+ ret |= mt9e013_t_focus_abs(sd, HOME_POS);
+
+ /* Program shading table into sensor */
+ ret |= mt9e013_write_reg_array(client, mt9e013_lens_shading);
+
+ /* restore settings */
+ mt9e013_res = mt9e013_res_preview;
+ N_RES = N_RES_PREVIEW;
+
+ return ret;
+}
+
+static void mt9e013_uninit(struct v4l2_subdev *sd)
+{
+ struct mt9e013_device *dev = to_mt9e013_sensor(sd);
+
+ dev->coarse_itg = 0;
+ dev->fine_itg = 0;
+ dev->gain = 0;
+ dev->focus = MT9E013_INVALID_CONFIG;
+}
+
+static int power_up(struct v4l2_subdev *sd)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9e013_device *dev = to_mt9e013_sensor(sd);
+ int ret;
+
+ /* power control */
+ ret = dev->platform_data->power_ctrl(sd, 1);
+ if (ret)
+ goto fail_power;
+
+ /* flis clock control */
+ ret = dev->platform_data->flisclk_ctrl(sd, 1);
+ if (ret)
+ goto fail_clk;
+
+ /* gpio ctrl */
+ ret = dev->platform_data->gpio_ctrl(sd, 1);
+ if (ret)
+ dev_err(&client->dev, "gpio failed 1\n");
+ msleep(20);
+
+ return 0;
+
+fail_clk:
+ dev->platform_data->flisclk_ctrl(sd, 0);
+fail_power:
+ dev->platform_data->power_ctrl(sd, 0);
+ dev_err(&client->dev, "sensor power-up failed\n");
+
+ return ret;
+}
+
+static int power_down(struct v4l2_subdev *sd)
+{
+ struct mt9e013_device *dev = to_mt9e013_sensor(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+
+ ret = dev->platform_data->flisclk_ctrl(sd, 0);
+ if (ret)
+ dev_err(&client->dev, "flisclk failed\n");
+
+ /* gpio ctrl */
+ ret = dev->platform_data->gpio_ctrl(sd, 0);
+ if (ret)
+ dev_err(&client->dev, "gpio failed 1\n");
+
+ /* power control */
+ ret = dev->platform_data->power_ctrl(sd, 0);
+ if (ret)
+ dev_err(&client->dev, "vprog failed.\n");
+
+ return ret;
+}
+
+static int mt9e013_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct mt9e013_device *dev = to_mt9e013_sensor(sd);
+ int ret;
+
+ if (on == 0) {
+ mt9e013_uninit(sd);
+ ret = power_down(sd);
+ dev->power = 0;
+ } else {
+ ret = power_up(sd);
+ if (!ret) {
+ dev->power = 1;
+ /* init motor initial position */
+ return mt9e013_init(sd, 0);
+ }
+ }
+
+ return ret;
+}
+
+static int mt9e013_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *chip)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (!chip)
+ return -EINVAL;
+
+ v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_MT9E013, 0);
+
+ return 0;
+}
+
+static int mt9e013_get_intg_factor(struct i2c_client *client,
+ struct camera_mipi_info *info,
+ const struct mt9e013_reg *reglist)
+{
+ sensor_register vt_pix_clk_div;
+ sensor_register vt_sys_clk_div;
+ sensor_register pre_pll_clk_div;
+ sensor_register pll_multiplier;
+ sensor_register op_pix_clk_div;
+ sensor_register op_sys_clk_div;
+
+ /* TODO: this should not be a constant but should be set by a call to
+ * MSIC's driver to get the ext_clk that MSIC supllies to the sensor.
+ */
+ const int ext_clk_freq_mhz = 19200000;
+ struct sensor_mode_data buf;
+ const struct mt9e013_reg *next = reglist;
+ int vt_pix_clk_freq_mhz;
+ u16 data[MT9E013_SHORT_MAX];
+
+ sensor_register coarse_integration_time_min;
+ sensor_register coarse_integration_time_max_margin;
+ sensor_register fine_integration_time_min;
+ sensor_register fine_integration_time_max_margin;
+ sensor_register frame_length_lines;
+ sensor_register line_length_pck;
+ sensor_register read_mode;
+
+ if (info == NULL)
+ return -EINVAL;
+
+ memset(data, 0, MT9E013_SHORT_MAX * sizeof(u16));
+ if (mt9e013_read_reg(client, 12, MT9E013_VT_PIX_CLK_DIV, data))
+ return -EINVAL;
+ vt_pix_clk_div = data[0];
+ vt_sys_clk_div = data[1];
+ pre_pll_clk_div = data[2];
+ pll_multiplier = data[3];
+ op_pix_clk_div = data[4];
+ op_sys_clk_div = data[5];
+
+ memset(data, 0, MT9E013_SHORT_MAX * sizeof(u16));
+ if (mt9e013_read_reg(client, 4, MT9E013_FRAME_LENGTH_LINES, data))
+ return -EINVAL;
+ frame_length_lines = data[0];
+ line_length_pck = data[1];
+
+ memset(data, 0, MT9E013_SHORT_MAX * sizeof(u16));
+ if (mt9e013_read_reg(client, 8, MT9E013_COARSE_INTG_TIME_MIN, data))
+ return -EINVAL;
+ coarse_integration_time_min = data[0];
+ coarse_integration_time_max_margin = data[1];
+ fine_integration_time_min = data[2];
+ fine_integration_time_max_margin = data[3];
+
+ memset(data, 0, MT9E013_SHORT_MAX * sizeof(u16));
+ if (mt9e013_read_reg(client, 2, MT9E013_READ_MODE, data))
+ return -EINVAL;
+ read_mode = data[0];
+
+ vt_pix_clk_freq_mhz = divsave_rounded(ext_clk_freq_mhz*pll_multiplier,
+ pre_pll_clk_div*vt_sys_clk_div*vt_pix_clk_div);
+
+ memset(data, 0, MT9E013_SHORT_MAX * sizeof(u16));
+ if (mt9e013_read_reg(client, 2, MT9E013_FINE_INTEGRATION_TIME, data))
+ return -EINVAL;
+ v4l2_info(client, "fine_integration_time_i2c: %d", data[0]);
+
+ for (; next->type != MT9E013_TOK_TERM; next++) {
+ if (next->type == MT9E013_16BIT) {
+ if (next->reg.sreg == MT9E013_FINE_INTEGRATION_TIME) {
+ buf.fine_integration_time_def = next->val;
+ break;
+ }
+ }
+ }
+
+ /* something's wrong here, this mode does not have fine_igt set! */
+ if (next->type == MT9E013_TOK_TERM)
+ return -EINVAL;
+
+ buf.coarse_integration_time_min = coarse_integration_time_min;
+ buf.coarse_integration_time_max_margin = coarse_integration_time_max_margin;
+ buf.fine_integration_time_min = fine_integration_time_min;
+ buf.fine_integration_time_max_margin = fine_integration_time_max_margin;
+ buf.vt_pix_clk_freq_mhz = vt_pix_clk_freq_mhz;
+ buf.line_length_pck = line_length_pck;
+ buf.frame_length_lines = frame_length_lines;
+ buf.read_mode = read_mode;
+
+ memcpy(&info->data, &buf, sizeof(buf));
+
+ return 0;
+}
+
+/* This returns the exposure time being used. This should only be used
+ for filling in EXIF data, not for actual image processing. */
+static int mt9e013_q_exposure(struct v4l2_subdev *sd, s32 *value)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ u16 coarse;
+ int ret;
+
+ /* the fine integration time is currently not calculated */
+ ret = mt9e013_read_reg(client, MT9E013_16BIT,
+ MT9E013_COARSE_INTEGRATION_TIME, &coarse);
+ *value = coarse;
+
+ return ret;
+}
+
+static int mt9e013_test_pattern(struct v4l2_subdev *sd, s32 value)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ return mt9e013_write_reg(client, MT9E013_16BIT, 0x3070, value);
+}
+
+static int mt9e013_v_flip(struct v4l2_subdev *sd, s32 value)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+
+ if (value > 1)
+ return -EINVAL;
+
+ ret = mt9e013_write_reg_array(client, mt9e013_param_hold);
+ if (ret)
+ return ret;
+ ret = mt9e013_rmw_reg(client, MT9E013_16BIT & ~MT9E013_RMW,
+ 0x3040, 0x8000, value);
+ if (ret)
+ return ret;
+ return mt9e013_write_reg_array(client, mt9e013_param_update);
+}
+
+
+static int mt9e013_t_vcm_slew(struct v4l2_subdev *sd, s32 value)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (value > MT9E013_VCM_SLEW_STEP_MAX)
+ return -EINVAL;
+
+ return mt9e013_rmw_reg(client, MT9E013_16BIT, MT9E013_VCM_SLEW_STEP,
+ MT9E013_VCM_SLEW_STEP_MASK, value);
+}
+
+static int mt9e013_t_vcm_timing(struct v4l2_subdev *sd, s32 value)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ /* Max 16 bits */
+ if (value > MT9E013_VCM_SLEW_TIME_MAX)
+ return -EINVAL;
+
+ return mt9e013_write_reg(client, MT9E013_16BIT, MT9E013_VCM_SLEW_TIME,
+ value);
+}
+
+static int mt9e013_g_focal(struct v4l2_subdev *sd, s32 *val)
+{
+ *val = (MT9E013_FOCAL_LENGTH_NUM << 16) | MT9E013_FOCAL_LENGTH_DEM;
+ return 0;
+}
+
+static int mt9e013_g_fnumber(struct v4l2_subdev *sd, s32 *val)
+{
+ /*const f number for mt9e013*/
+ *val = (MT9E013_F_NUMBER_DEFAULT_NUM << 16) | MT9E013_F_NUMBER_DEM;
+ return 0;
+}
+
+static int mt9e013_g_fnumber_range(struct v4l2_subdev *sd, s32 *val)
+{
+ *val = (MT9E013_F_NUMBER_DEFAULT_NUM << 24) |
+ (MT9E013_F_NUMBER_DEM << 16) |
+ (MT9E013_F_NUMBER_DEFAULT_NUM << 8) | MT9E013_F_NUMBER_DEM;
+ return 0;
+}
+
+struct mt9e013_control mt9e013_controls[] = {
+ {
+ .qc = {
+ .id = V4L2_CID_EXPOSURE_ABSOLUTE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "exposure",
+ .minimum = 0x0,
+ .maximum = 0xffff,
+ .step = 0x01,
+ .default_value = 0x00,
+ .flags = 0,
+ },
+ .query = mt9e013_q_exposure,
+ },
+ {
+ .qc = {
+ .id = V4L2_CID_TEST_PATTERN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Test pattern",
+ .minimum = 0,
+ .maximum = 0xffff,
+ .step = 1,
+ .default_value = 0,
+ },
+ .tweak = mt9e013_test_pattern,
+ },
+ {
+ .qc = {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ .tweak = mt9e013_v_flip,
+ },
+ {
+ .qc = {
+ .id = V4L2_CID_FOCUS_ABSOLUTE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "focus move absolute",
+ .minimum = 0,
+ .maximum = MT9E013_MAX_FOCUS_POS,
+ .step = 1,
+ .default_value = 0,
+ .flags = 0,
+ },
+ .tweak = mt9e013_t_focus_abs,
+ .query = mt9e013_q_focus_abs,
+ },
+ {
+ .qc = {
+ .id = V4L2_CID_FOCUS_RELATIVE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "focus move relative",
+ .minimum = MT9E013_MAX_FOCUS_NEG,
+ .maximum = MT9E013_MAX_FOCUS_POS,
+ .step = 1,
+ .default_value = 0,
+ .flags = 0,
+ },
+ .tweak = mt9e013_t_focus_rel,
+ },
+ {
+ .qc = {
+ .id = V4L2_CID_FOCUS_STATUS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "focus status",
+ .minimum = 0,
+ .maximum = 100, /* allow enum to grow in the future */
+ .step = 1,
+ .default_value = 0,
+ .flags = 0,
+ },
+ .query = mt9e013_q_focus_status,
+ },
+ {
+ .qc = {
+ .id = V4L2_CID_VCM_SLEW,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "vcm slew",
+ .minimum = 0,
+ .maximum = MT9E013_VCM_SLEW_STEP_MAX,
+ .step = 1,
+ .default_value = 0,
+ .flags = 0,
+ },
+ .tweak = mt9e013_t_vcm_slew,
+ },
+ {
+ .qc = {
+ .id = V4L2_CID_VCM_TIMEING,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "vcm step time",
+ .minimum = 0,
+ .maximum = MT9E013_VCM_SLEW_TIME_MAX,
+ .step = 1,
+ .default_value = 0,
+ .flags = 0,
+ },
+ .tweak = mt9e013_t_vcm_timing,
+ },
+ {
+ .qc = {
+ .id = V4L2_CID_FOCAL_ABSOLUTE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "focal length",
+ .minimum = MT9E013_FOCAL_LENGTH_DEFAULT,
+ .maximum = MT9E013_FOCAL_LENGTH_DEFAULT,
+ .step = 0x01,
+ .default_value = MT9E013_FOCAL_LENGTH_DEFAULT,
+ .flags = 0,
+ },
+ .query = mt9e013_g_focal,
+ },
+ {
+ .qc = {
+ .id = V4L2_CID_FNUMBER_ABSOLUTE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "f-number",
+ .minimum = MT9E013_F_NUMBER_DEFAULT,
+ .maximum = MT9E013_F_NUMBER_DEFAULT,
+ .step = 0x01,
+ .default_value = MT9E013_F_NUMBER_DEFAULT,
+ .flags = 0,
+ },
+ .query = mt9e013_g_fnumber,
+ },
+ {
+ .qc = {
+ .id = V4L2_CID_FNUMBER_RANGE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "f-number range",
+ .minimum = MT9E013_F_NUMBER_RANGE,
+ .maximum = MT9E013_F_NUMBER_RANGE,
+ .step = 0x01,
+ .default_value = MT9E013_F_NUMBER_RANGE,
+ .flags = 0,
+ },
+ .query = mt9e013_g_fnumber_range,
+ }
+};
+#define N_CONTROLS (ARRAY_SIZE(mt9e013_controls))
+
+static struct mt9e013_control *mt9e013_find_control(u32 id)
+{
+ int i;
+
+ for (i = 0; i < N_CONTROLS; i++)
+ if (mt9e013_controls[i].qc.id == id)
+ return &mt9e013_controls[i];
+ return NULL;
+}
+
+static int mt9e013_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+ struct mt9e013_control *ctrl = mt9e013_find_control(qc->id);
+
+ if (ctrl == NULL)
+ return -EINVAL;
+
+ *qc = ctrl->qc;
+
+ return 0;
+}
+
+/* mt9e013 control set/get */
+static int mt9e013_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+ struct mt9e013_control *s_ctrl;
+
+ if (!ctrl)
+ return -EINVAL;
+
+ s_ctrl = mt9e013_find_control(ctrl->id);
+ if ((s_ctrl == NULL) || (s_ctrl->query == NULL))
+ return -EINVAL;
+
+ return s_ctrl->query(sd, &ctrl->value);
+}
+
+static int mt9e013_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+ struct mt9e013_control *octrl = mt9e013_find_control(ctrl->id);
+
+ if ((octrl == NULL) || (octrl->tweak == NULL))
+ return -EINVAL;
+
+ return octrl->tweak(sd, ctrl->value);
+}
+
+struct mt9e013_format mt9e013_formats[] = {
+ {
+ .desc = "RGB Bayer Format",
+ .regs = NULL,
+ },
+};
+
+/*
+ * distance - calculate the distance
+ * @res: resolution
+ * @w: width
+ * @h: height
+ *
+ * Get the gap between resolution and w/h.
+ * res->width/height smaller than w/h wouldn't be considered.
+ * Returns the value of gap or -1 if fail.
+ */
+#define LARGEST_ALLOWED_RATIO_MISMATCH 140 /* tune this value so that the DVS resolutions get selected properly, but make sure 16:9 do not match 4:3*/
+static int distance(struct mt9e013_resolution *res, u32 w, u32 h)
+{
+ unsigned int w_ratio = ((res->width<<13)/w);
+ unsigned int h_ratio = ((res->height<<13)/h);
+ int match = abs(((w_ratio<<13)/h_ratio) - ((int)8192));
+
+ if ((w_ratio < (int)8192) || (h_ratio < (int)8192) || (match > LARGEST_ALLOWED_RATIO_MISMATCH))
+ return -1;
+
+ return w_ratio + h_ratio;
+}
+
+/* Return the nearest higher resolution index */
+static int nearest_resolution_index(int w, int h)
+{
+ int i;
+ int idx = -1;
+ int dist;
+ int min_dist = INT_MAX;
+ struct mt9e013_resolution *tmp_res = NULL;
+
+ for (i = 0; i < N_RES; i++) {
+ tmp_res = &mt9e013_res[i];
+ dist = distance(tmp_res, w, h);
+ if (dist == -1)
+ continue;
+ if (dist < min_dist) {
+ min_dist = dist;
+ idx = i;
+ }
+ }
+
+ if (idx == -1)
+ return -1;
+
+ return idx;
+}
+
+static int get_resolution_index(int w, int h)
+{
+ int i;
+
+ for (i = 0; i < N_RES; i++) {
+ if (w != mt9e013_res[i].width)
+ continue;
+ if (h != mt9e013_res[i].height)
+ continue;
+ /* Found it */
+ return i;
+ }
+ return -1;
+}
+
+static int mt9e013_try_mbus_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *fmt)
+{
+ int idx;
+
+ if (!fmt)
+ return -EINVAL;
+
+ if ((fmt->width > MT9E013_RES_WIDTH_MAX) || (fmt->height > MT9E013_RES_HEIGHT_MAX)) {
+ fmt->width = MT9E013_RES_WIDTH_MAX;
+ fmt->height = MT9E013_RES_HEIGHT_MAX;
+ } else {
+ idx = nearest_resolution_index(fmt->width, fmt->height);
+
+ /*
+ * nearest_resolution_index() doesn't return smaller resolutions.
+ * If it fails, it means the requested resolution is higher than we
+ * can support. Fallback to highest possible resolution in this case.
+ */
+ if (idx == -1)
+ idx = N_RES - 1;
+
+ fmt->width = mt9e013_res[idx].width;
+ fmt->height = mt9e013_res[idx].height;
+ }
+
+ fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+
+
+ return 0;
+}
+
+static int mt9e013_s_mbus_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *fmt)
+{
+ struct mt9e013_device *dev = to_mt9e013_sensor(sd);
+ const struct mt9e013_reg *mt9e013_def_reg;
+ struct camera_mipi_info *mt9e013_info = NULL;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+
+ mt9e013_info = v4l2_get_subdev_hostdata(sd);
+ if (mt9e013_info == NULL)
+ return -EINVAL;
+
+ ret = mt9e013_try_mbus_fmt(sd, fmt);
+ if (ret) {
+ v4l2_err(sd, "try fmt fail\n");
+ return ret;
+ }
+ dev->fmt_idx = get_resolution_index(fmt->width, fmt->height);
+
+ /* Sanity check */
+ if (unlikely(dev->fmt_idx == -1)) {
+ v4l2_err(sd, "get resolution fail\n");
+ return -EINVAL;
+ }
+
+ mt9e013_def_reg = mt9e013_res[dev->fmt_idx].regs;
+ ret = mt9e013_write_reg_array(client, mt9e013_def_reg);
+ if (ret)
+ return -EINVAL;
+
+ ret = mt9e013_get_intg_factor(client, mt9e013_info, mt9e013_def_reg);
+ if (ret) {
+ v4l2_err(sd, "failed to get integration_factor\n");
+ return -EINVAL;
+ }
+
+ /* restore exposure, gain settings */
+ if (dev->coarse_itg)
+ mt9e013_set_exposure(sd, dev->coarse_itg, dev->fine_itg,
+ dev->gain);
+
+ return 0;
+}
+
+static int mt9e013_g_mbus_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *fmt)
+{
+ struct mt9e013_device *dev = to_mt9e013_sensor(sd);
+
+ if (!fmt)
+ return -EINVAL;
+
+ fmt->width = mt9e013_res[dev->fmt_idx].width;
+ fmt->height = mt9e013_res[dev->fmt_idx].height;
+ fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+
+ return 0;
+}
+
+static int mt9e013_detect(struct i2c_client *client, u16 *id, u8 *revision)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ u16 high, low;
+
+ /* i2c check */
+ if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
+ return -ENODEV;
+
+ /* check sensor chip ID */
+ if (mt9e013_read_reg(client, MT9E013_8BIT, MT9E013_SC_CMMN_CHIP_ID_H,
+ &high)) {
+ v4l2_err(client, "sensor_id_high = 0x%x\n", high);
+ return -ENODEV;
+ }
+ if (mt9e013_read_reg(client, MT9E013_8BIT, MT9E013_SC_CMMN_CHIP_ID_L,
+ &low)) {
+ v4l2_err(client, "sensor_id_low = 0x%x\n", high);
+ return -ENODEV;
+ }
+ *id = (((u8) high) << 8) | (u8) low;
+ v4l2_info(client, "sensor_id = 0x%x\n", *id);
+ real_model_id = *id;
+
+ if (*id != MT9E013_ID) {
+ v4l2_err(client, "sensor ID error\n");
+ return -ENODEV;
+ }
+
+ v4l2_info(client, "detect mt9e013 success\n");
+
+ /* REVISIT: HACK: Driver is currently forcing revision to 0 */
+ *revision = 0;
+
+ return 0;
+}
+
+/*
+ * mt9e013 stream on/off
+ */
+static int mt9e013_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ int ret;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9e013_device *dev = to_mt9e013_sensor(sd);
+ u16 temp;
+
+ if (enable) {
+ if (dev->sensor_revision <= 0x0) {
+ /* begin: vcm hack, needs to be removed when new camera module is availible */
+ struct mt9e013_reg mt9e013_stream_enable[] = {
+ mt9e013_streaming[0],
+ {MT9E013_16BIT, {0x30F2}, 0x0000}, /* VCM_NEW_CODE */
+ INIT_VCM_CONTROL,
+ {MT9E013_16BIT, {0x30F2}, 0x0000}, /* VCM_NEW_CODE */
+ {MT9E013_TOK_DELAY, {0}, 100},
+ {MT9E013_TOK_TERM, {0}, 0}
+ };
+
+ mt9e013_stream_enable[1].val = (MT9E013_MAX_FOCUS_POS - dev->focus) + 1;
+ mt9e013_stream_enable[3].val = (MT9E013_MAX_FOCUS_POS - dev->focus);
+
+ ret = mt9e013_write_reg_array(client, mt9e013_stream_enable);
+
+ /* end: vcm hack, needs to be removed when new camera module is availible */
+ } else {
+ ret = mt9e013_write_reg_array(client, mt9e013_streaming);
+ }
+
+ if (ret != 0) {
+ v4l2_err(client, "write_reg_array err\n");
+ return ret;
+ }
+ dev->streaming = 1;
+ } else {
+
+ ret = mt9e013_write_reg_array(client, mt9e013_soft_standby);
+ if (ret != 0) {
+ v4l2_err(client, "write_reg_array err\n");
+ return ret;
+ }
+ dev->streaming = 0;
+ }
+
+ /* restore settings */
+ mt9e013_res = mt9e013_res_preview;
+ N_RES = N_RES_PREVIEW;
+
+ return 0;
+}
+
+/*
+ * mt9e013 enum frame size, frame intervals
+ */
+static int mt9e013_enum_framesizes(struct v4l2_subdev *sd,
+ struct v4l2_frmsizeenum *fsize)
+{
+ unsigned int index = fsize->index;
+
+ if (index >= N_RES)
+ return -EINVAL;
+
+ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+ fsize->discrete.width = mt9e013_res[index].width;
+ fsize->discrete.height = mt9e013_res[index].height;
+ fsize->reserved[0] = mt9e013_res[index].used;
+
+ return 0;
+}
+
+static int mt9e013_enum_frameintervals(struct v4l2_subdev *sd,
+ struct v4l2_frmivalenum *fival)
+{
+ unsigned int index = fival->index;
+
+ if (index >= N_RES)
+ return -EINVAL;
+
+ /* since the isp will donwscale the resolution to the right size, find the nearest one that will allow the isp to do so
+ * important to ensure that the resolution requested is padded correctly by the requester, which is the atomisp driver in this case.
+ */
+ index = nearest_resolution_index(fival->width, fival->height);
+
+ if (-1 == index)
+ return -EINVAL;
+
+ fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+/* fival->width = mt9e013_res[index].width;
+ fival->height = mt9e013_res[index].height; */
+ fival->discrete.numerator = 1;
+ fival->discrete.denominator = mt9e013_res[index].fps;
+
+ return 0;
+}
+
+static int mt9e013_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index,
+ enum v4l2_mbus_pixelcode *code)
+{
+ *code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ return 0;
+}
+
+static int mt9e013_s_config(struct v4l2_subdev *sd,
+ int irq, void *pdata)
+{
+ struct mt9e013_device *dev = to_mt9e013_sensor(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ u8 sensor_revision;
+ u16 sensor_id;
+ int ret;
+
+ if (pdata == NULL)
+ return -ENODEV;
+
+ dev->platform_data = pdata;
+
+ ret = mt9e013_s_power(sd, 1);
+ if (ret) {
+ v4l2_err(client, "mt9e013 power-up err.\n");
+ return ret;
+ }
+
+ ret = dev->platform_data->csi_cfg(sd, 1);
+ if (ret)
+ goto fail_csi_cfg;
+
+ /* config & detect sensor */
+ ret = mt9e013_detect(client, &sensor_id, &sensor_revision);
+ if (ret) {
+ v4l2_err(client, "mt9e013_detect err s_config.\n");
+ goto fail_detect;
+ }
+
+ dev->sensor_id = sensor_id;
+ dev->sensor_revision = sensor_revision;
+
+ /* power off sensor */
+ ret = mt9e013_s_power(sd, 0);
+ if (ret) {
+ v4l2_err(client, "mt9e013 power-down err.\n");
+ return ret;
+ }
+
+ return 0;
+
+fail_detect:
+ dev->platform_data->csi_cfg(sd, 0);
+fail_csi_cfg:
+ mt9e013_s_power(sd, 0);
+ dev_err(&client->dev, "sensor power-gating failed\n");
+ return ret;
+}
+
+static int
+mt9e013_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->index >= MAX_FMTS)
+ return -EINVAL;
+ code->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+
+ return 0;
+}
+
+static int
+mt9e013_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ int index = fse->index;
+
+ if (index >= N_RES)
+ return -EINVAL;
+
+ fse->min_width = mt9e013_res[index].width;
+ fse->min_height = mt9e013_res[index].height;
+ fse->max_width = mt9e013_res[index].width;
+ fse->max_height = mt9e013_res[index].height;
+
+ return 0;
+}
+
+static struct v4l2_mbus_framefmt *
+__mt9e013_get_pad_format(struct mt9e013_device *sensor,
+ struct v4l2_subdev_fh *fh, unsigned int pad,
+ enum v4l2_subdev_format_whence which)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd);
+
+ if (pad != 0) {
+ v4l2_err(client, "%s err. pad %x\n", __func__, pad);
+ return NULL;
+ }
+
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_format(fh, pad);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return &sensor->format;
+ default:
+ return NULL;
+ }
+}
+
+static int
+mt9e013_get_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct mt9e013_device *dev = to_mt9e013_sensor(sd);
+ struct v4l2_mbus_framefmt *format =
+ __mt9e013_get_pad_format(dev, fh, fmt->pad, fmt->which);
+
+ if (format == NULL)
+ return -EINVAL;
+ fmt->format = *format;
+
+ return 0;
+}
+
+static int
+mt9e013_set_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct mt9e013_device *dev = to_mt9e013_sensor(sd);
+ struct v4l2_mbus_framefmt *format =
+ __mt9e013_get_pad_format(dev, fh, fmt->pad, fmt->which);
+
+ if (format == NULL)
+ return -EINVAL;
+ if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+ dev->format = fmt->format;
+
+ return 0;
+}
+
+static int
+mt9e013_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *param)
+{
+ struct mt9e013_device *dev = to_mt9e013_sensor(sd);
+
+ dev->run_mode = param->parm.capture.capturemode;
+
+ switch (dev->run_mode) {
+ case CI_MODE_VIDEO:
+ mt9e013_res = mt9e013_res_video;
+ N_RES = N_RES_VIDEO;
+ break;
+ case CI_MODE_STILL_CAPTURE:
+ mt9e013_res = mt9e013_res_still;
+ N_RES = N_RES_STILL;
+ break;
+ default:
+ mt9e013_res = mt9e013_res_preview;
+ N_RES = N_RES_PREVIEW;
+ }
+ return 0;
+}
+
+static const struct v4l2_subdev_video_ops mt9e013_video_ops = {
+ .s_stream = mt9e013_s_stream,
+ .enum_framesizes = mt9e013_enum_framesizes,
+ .enum_frameintervals = mt9e013_enum_frameintervals,
+ .enum_mbus_fmt = mt9e013_enum_mbus_fmt,
+ .try_mbus_fmt = mt9e013_try_mbus_fmt,
+ .g_mbus_fmt = mt9e013_g_mbus_fmt,
+ .s_mbus_fmt = mt9e013_s_mbus_fmt,
+ .s_parm = mt9e013_s_parm,
+};
+
+static const struct v4l2_subdev_core_ops mt9e013_core_ops = {
+ .g_chip_ident = mt9e013_g_chip_ident,
+ .s_config = mt9e013_s_config,
+ .queryctrl = mt9e013_queryctrl,
+ .g_ctrl = mt9e013_g_ctrl,
+ .s_ctrl = mt9e013_s_ctrl,
+ .s_power = mt9e013_s_power,
+ .ioctl = mt9e013_ioctl,
+ .init = mt9e013_init,
+};
+
+/* REVISIT: Do we need pad operations? */
+static const struct v4l2_subdev_pad_ops mt9e013_pad_ops = {
+ .enum_mbus_code = mt9e013_enum_mbus_code,
+ .enum_frame_size = mt9e013_enum_frame_size,
+ .get_fmt = mt9e013_get_pad_format,
+ .set_fmt = mt9e013_set_pad_format,
+};
+
+static const struct v4l2_subdev_ops mt9e013_ops = {
+ .core = &mt9e013_core_ops,
+ .video = &mt9e013_video_ops,
+ .pad = &mt9e013_pad_ops,
+};
+
+static const struct media_entity_operations mt9e013_entity_ops = {
+ .set_power = v4l2_subdev_set_power,
+};
+
+static int mt9e013_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct mt9e013_device *dev = to_mt9e013_sensor(sd);
+
+ dev->platform_data->csi_cfg(sd, 0);
+ v4l2_device_unregister_subdev(sd);
+ kfree(dev);
+
+ return 0;
+}
+
+static int mt9e013_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct mt9e013_device *dev;
+ int ret;
+
+ /* allocate sensor device & init sub device */
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev) {
+ v4l2_err(client, "%s: out of memory\n", __func__);
+ return -ENOMEM;
+ }
+
+ dev->fmt_idx = 0;
+ v4l2_i2c_subdev_init(&(dev->sd), client, &mt9e013_ops);
+
+ dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ dev->pad.flags = MEDIA_PAD_FLAG_OUTPUT;
+ dev->sd.entity.ops = &mt9e013_entity_ops;
+ dev->format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+
+ /* REVISIT: Do we need media controller? */
+ ret = media_entity_init(&dev->sd.entity, 1, &dev->pad, 0);
+ if (ret) {
+ mt9e013_remove(client);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct i2c_device_id mt9e013_id[] = {
+ {MT9E013_NAME, 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, mt9e013_id);
+
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = MT9E013_NAME,
+ .probe = mt9e013_probe,
+ .remove = mt9e013_remove,
+ .id_table = mt9e013_id,
+};
+
+MODULE_DESCRIPTION("A low-level driver for Aptina MT9E013 sensors");
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * Support for Aptina MT9E013 camera sensor.
+ *
+ * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+/* NOT FOR INTEGRATION ! DO NOT ADD TO ANDORID GIT TREE */
+
+#ifndef __MT9E013_H__
+#define __MT9E013_H__
+#include <linux/atomisp_platform.h>
+#include <linux/atomisp.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/videodev2.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/types.h>
+#include <media/media-entity.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+
+#define MT9E013_NAME "mt9e013"
+#define MT9E013_ADDR 0x36
+#define MT9E013_ID 0x4b00
+
+#define LAST_REG_SETING {0xffff, 0xff}
+#define is_last_reg_setting(item) ((item).reg == 0xffff)
+#define I2C_MSG_LENGTH 0x2
+
+#define MT9E013_INVALID_CONFIG 0xffffffff
+
+#define MT9E013_MAX_FOCUS_POS 255
+#define MT9E013_MAX_FOCUS_NEG (-255)
+
+#define MT9E013_INTG_UNIT_US 100
+#define MT9E013_MCLK 192
+
+#define MT9E013_REG_BITS 16
+#define MT9E013_REG_MASK 0xFFFF
+
+/* This should be added into include/linux/videodev2.h */
+#ifndef V4L2_IDENT_MT9E013
+#define V4L2_IDENT_MT9E013 8245
+#endif
+
+/*
+ * mt9e013 System control registers
+ */
+#define MT9E013_SC_CMMN_CHIP_ID_H 0x0000
+#define MT9E013_SC_CMMN_CHIP_ID_L 0x0001
+
+#define GROUPED_PARAMETER_UPDATE 0x0000
+#define GROUPED_PARAMETER_HOLD 0x0100
+#define MT9E013_GROUPED_PARAMETER_HOLD 0x0104
+
+#define MT9E013_VT_PIX_CLK_DIV 0x0300
+#define MT9E013_VT_SYS_CLK_DIV 0x0302
+#define MT9E013_PRE_PLL_CLK_DIV 0x0304
+#define MT9E013_PLL_MULTIPLIER 0x0306
+#define MT9E013_OP_PIX_DIV 0x0308
+#define MT9E013_OP_SYS_DIV 0x030A
+#define MT9E013_FRAME_LENGTH_LINES 0x0340
+#define MT9E013_LINE_LENGTH_PCK 0x0342
+#define MT9E013_COARSE_INTG_TIME_MIN 0x1004
+#define MT9E013_COARSE_INTG_TIME_MAX 0x1006
+#define MT9E013_FINE_INTG_TIME_MIN 0x1008
+#define MT9E013_FINE_INTG_MIN_DEF 0x4FE
+#define MT9E013_FINE_INTG_TIME_MAX 0x100A
+#define MT9E013_FINE_INTG_MAX_DEF 0x3EE
+
+#define MT9E013_READ_MODE 0x3040
+
+
+#define MT9E013_COARSE_INTEGRATION_TIME 0x3012
+#define MT9E013_FINE_INTEGRATION_TIME 0x3014
+#define MT9E013_ROW_SPEED 0x3016
+#define MT9E013_GLOBAL_GAIN 0x305e
+#define MT9E013_GLOBAL_GAIN_WR 0x1000
+#define MT9E013_TEST_PATTERN_MODE 0x3070
+#define MT9E013_VCM_SLEW_STEP 0x30F0
+#define MT9E013_VCM_SLEW_STEP_MAX 0x7
+#define MT9E013_VCM_SLEW_STEP_MASK 0x7
+#define MT9E013_VCM_CODE 0x30F2
+#define MT9E013_VCM_SLEW_TIME 0x30F4
+#define MT9E013_VCM_SLEW_TIME_MAX 0xffff
+#define MT9E013_VCM_ENABLE 0x8000
+
+/* mt9e013 SCCB */
+#define MT9E013_SCCB_CTRL 0x3100
+#define MT9E013_AEC_PK_EXPO_H 0x3500
+#define MT9E013_AEC_PK_EXPO_M 0x3501
+#define MT9E013_AEC_PK_EXPO_L 0x3502
+#define MT9E013_AEC_MANUAL_CTRL 0x3503
+#define MT9E013_AGC_ADJ_H 0x3508
+#define MT9E013_AGC_ADJ_L 0x3509
+
+#define MT9E013_FOCAL_LENGTH_NUM 439 /*4.39mm*/
+#define MT9E013_FOCAL_LENGTH_DEM 100
+#define MT9E013_F_NUMBER_DEFAULT_NUM 24
+#define MT9E013_F_NUMBER_DEM 10
+
+#define MT9E013_X_ADDR_MIN 0X1180
+#define MT9E013_Y_ADDR_MIN 0X1182
+#define MT9E013_X_ADDR_MAX 0X1184
+#define MT9E013_Y_ADDR_MAX 0X1186
+
+#define MT9E013_MIN_FRAME_LENGTH_LINES 0x1140
+#define MT9E013_MAX_FRAME_LENGTH_LINES 0x1142
+#define MT9E013_MIN_LINE_LENGTH_PCK 0x1144
+#define MT9E013_MAX_LINE_LENGTH_PCK 0x1146
+#define MT9E013_MIN_LINE_BLANKING_PCK 0x1148
+#define MT9E013_MIN_FRAME_BLANKING_LINES 0x114A
+#define MT9E013_X_OUTPUT_SIZE 0x034C
+#define MT9E013_Y_OUTPUT_SIZE 0x034E
+
+
+/*
+ * focal length bits definition:
+ * bits 31-16: numerator, bits 15-0: denominator
+ */
+#define MT9E013_FOCAL_LENGTH_DEFAULT 0x1B70064
+
+/*
+ * current f-number bits definition:
+ * bits 31-16: numerator, bits 15-0: denominator
+ */
+#define MT9E013_F_NUMBER_DEFAULT 0x18000a
+
+/*
+ * f-number range bits definition:
+ * bits 31-24: max f-number numerator
+ * bits 23-16: max f-number denominator
+ * bits 15-8: min f-number numerator
+ * bits 7-0: min f-number denominator
+ */
+#define MT9E013_F_NUMBER_RANGE 0x180a180a
+#define OTPM_ADD_START_1 0x1000
+#define OTPM_DATA_LENGTH_1 0x0100
+#define OTPM_COUNT 0x200
+
+/* Defines for register writes and register array processing */
+#define MT9E013_BYTE_MAX 32
+#define MT9E013_SHORT_MAX 16
+#define I2C_RETRY_COUNT 5
+#define MT9E013_TOK_MASK 0xfff0
+
+#define MT9E013_STATUS_POWER_DOWN 0x0
+#define MT9E013_STATUS_STANDBY 0x2
+#define MT9E013_STATUS_ACTIVE 0x3
+#define MT9E013_STATUS_VIEWFINDER 0x4
+
+#define v4l2_format_capture_type_entry(_width, _height, \
+ _pixelformat, _bytesperline, _colorspace) \
+ {\
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,\
+ .fmt.pix.width = (_width),\
+ .fmt.pix.height = (_height),\
+ .fmt.pix.pixelformat = (_pixelformat),\
+ .fmt.pix.bytesperline = (_bytesperline),\
+ .fmt.pix.colorspace = (_colorspace),\
+ .fmt.pix.sizeimage = (_height)*(_bytesperline),\
+ }
+
+#define s_output_format_entry(_width, _height, _pixelformat, \
+ _bytesperline, _colorspace, _fps) \
+ {\
+ .v4l2_fmt = v4l2_format_capture_type_entry(_width, \
+ _height, _pixelformat, _bytesperline, \
+ _colorspace),\
+ .fps = (_fps),\
+ }
+
+#define s_output_format_reg_entry(_width, _height, _pixelformat, \
+ _bytesperline, _colorspace, _fps, _reg_setting) \
+ {\
+ .s_fmt = s_output_format_entry(_width, _height,\
+ _pixelformat, _bytesperline, \
+ _colorspace, _fps),\
+ .reg_setting = (_reg_setting),\
+ }
+
+struct s_ctrl_id {
+ struct v4l2_queryctrl qc;
+ int (*s_ctrl)(struct v4l2_subdev *sd, u32 val);
+ int (*g_ctrl)(struct v4l2_subdev *sd, u32 *val);
+};
+
+#define v4l2_queryctrl_entry_integer(_id, _name,\
+ _minimum, _maximum, _step, \
+ _default_value, _flags) \
+ {\
+ .id = (_id), \
+ .type = V4L2_CTRL_TYPE_INTEGER, \
+ .name = _name, \
+ .minimum = (_minimum), \
+ .maximum = (_maximum), \
+ .step = (_step), \
+ .default_value = (_default_value),\
+ .flags = (_flags),\
+ }
+#define v4l2_queryctrl_entry_boolean(_id, _name,\
+ _default_value, _flags) \
+ {\
+ .id = (_id), \
+ .type = V4L2_CTRL_TYPE_BOOLEAN, \
+ .name = _name, \
+ .minimum = 0, \
+ .maximum = 1, \
+ .step = 1, \
+ .default_value = (_default_value),\
+ .flags = (_flags),\
+ }
+
+#define s_ctrl_id_entry_integer(_id, _name, \
+ _minimum, _maximum, _step, \
+ _default_value, _flags, \
+ _s_ctrl, _g_ctrl) \
+ {\
+ .qc = v4l2_queryctrl_entry_integer(_id, _name,\
+ _minimum, _maximum, _step,\
+ _default_value, _flags), \
+ .s_ctrl = _s_ctrl, \
+ .g_ctrl = _g_ctrl, \
+ }
+
+#define s_ctrl_id_entry_boolean(_id, _name, \
+ _default_value, _flags, \
+ _s_ctrl, _g_ctrl) \
+ {\
+ .qc = v4l2_queryctrl_entry_boolean(_id, _name,\
+ _default_value, _flags), \
+ .s_ctrl = _s_ctrl, \
+ .g_ctrl = _g_ctrl, \
+ }
+
+
+#define macro_string_entry(VAL) \
+ { \
+ .val = VAL, \
+ .string = #VAL, \
+ }
+
+enum mt9e013_tok_type {
+ MT9E013_8BIT = 0x0001,
+ MT9E013_16BIT = 0x0002,
+ MT9E013_RMW = 0x0010,
+ MT9E013_TOK_TERM = 0xf000, /* terminating token for reg list */
+ MT9E013_TOK_DELAY = 0xfe00 /* delay token for reg list */
+};
+
+/*
+ * If register address or register width is not 32 bit width,
+ * user needs to convert it manually
+ */
+
+struct s_register_setting {
+ u32 reg;
+ u32 val;
+};
+
+struct s_output_format {
+ struct v4l2_format v4l2_fmt;
+ int fps;
+};
+
+/**
+ * struct mt9e013_fwreg - Firmware burst command
+ * @type: FW burst or 8/16 bit register
+ * @addr: 16-bit offset to register or other values depending on type
+ * @val: data value for burst (or other commands)
+ *
+ * Define a structure for sensor register initialization values
+ */
+struct mt9e013_fwreg {
+ enum mt9e013_tok_type type; /* value, register or FW burst string */
+ u16 addr; /* target address */
+ u32 val[8];
+};
+
+/**
+ * struct mt9e013_reg - MI sensor register format
+ * @type: type of the register
+ * @reg: 16-bit offset to register
+ * @val: 8/16/32-bit register value
+ *
+ * Define a structure for sensor register initialization values
+ */
+struct mt9e013_reg {
+ enum mt9e013_tok_type type;
+ union {
+ u16 sreg;
+ struct mt9e013_fwreg *fwreg;
+ } reg;
+ u32 val; /* @set value for read/mod/write, @mask */
+ u32 val2; /* optional: for rmw, OR mask */
+};
+
+/* Store macro values' debug names */
+struct macro_string {
+ u8 val;
+ char *string;
+};
+
+static inline const char *
+macro_to_string(const struct macro_string *array, int size, u8 val)
+{
+ int i;
+ for (i = 0; i < size; i++) {
+ if (array[i].val == val)
+ return array[i].string;
+ }
+ return "Unknown VAL";
+}
+
+struct mt9e013_control {
+ struct v4l2_queryctrl qc;
+ int (*query)(struct v4l2_subdev *sd, s32 *value);
+ int (*tweak)(struct v4l2_subdev *sd, s32 value);
+};
+
+struct mt9e013_resolution {
+ u8 *desc;
+ int res;
+ int width;
+ int height;
+ int fps;
+ bool used;
+ const struct mt9e013_reg *regs;
+};
+
+struct mt9e013_format {
+ u8 *desc;
+ u32 pixelformat;
+ struct s_register_setting *regs;
+};
+
+
+/* mt9e013 device structure */
+struct mt9e013_device {
+ struct v4l2_subdev sd;
+ struct media_pad pad;
+ struct v4l2_mbus_framefmt format;
+
+ struct camera_sensor_platform_data *platform_data;
+ int fmt_idx;
+ int status;
+ int streaming;
+ int power;
+ u8 res;
+ u8 type;
+ u16 sensor_id;
+ u8 sensor_revision;
+ u16 coarse_itg;
+ u16 fine_itg;
+ u16 gain;
+ u32 focus;
+ int run_mode;
+ struct timeval timestamp_t_focus_abs;
+
+};
+
+#define MT9E013_MAX_WRITE_BUF_SIZE 128
+struct mt9e013_write_buffer {
+ u16 addr;
+ u8 data[MT9E013_MAX_WRITE_BUF_SIZE];
+};
+
+struct mt9e013_write_ctrl {
+ int index;
+ struct mt9e013_write_buffer buffer;
+};
+
+#define MT9E013_OTP_START_ADDR 0x3800
+#define MT9E013_OTP_DATA_SIZE 456
+#define MT9E013_OTP_READY_REG 0x304a
+#define MT9E013_OTP_READY_REG_DONE (1 << 5)
+#define MT9E013_OTP_READY_REG_OK (1 << 6)
+
+static const struct mt9e013_reg mt9e013_otp_type30[] = {
+ {MT9E013_16BIT, {0x3134}, 0xcd95},
+ {MT9E013_16BIT, {0x304c}, 0x3000},
+ {MT9E013_16BIT, {0x304a}, 0x0010},
+ {MT9E013_TOK_TERM, {0}, 0}
+};
+
+static const struct mt9e013_reg mt9e013_otp_type31[] = {
+ {MT9E013_16BIT, {0x3134}, 0xcd95},
+ {MT9E013_16BIT, {0x304c}, 0x3100},
+ {MT9E013_16BIT, {0x304a}, 0x0010},
+ {MT9E013_TOK_TERM, {0}, 0}
+};
+
+static const struct mt9e013_reg mt9e013_otp_type32[] = {
+ {MT9E013_16BIT, {0x3134}, 0xcd95},
+ {MT9E013_16BIT, {0x304c}, 0x3200},
+ {MT9E013_16BIT, {0x304a}, 0x0010},
+ {MT9E013_TOK_TERM, {0}, 0}
+};
+
+#define MT9E013_OTP_CHECKSUM 1
+#define MT9E013_OTP_MOD_CHECKSUM 255
+
+/*
+ * Checksum entries in OTP data:
+ * @start: start offset of checksum's input data
+ * @end: end offset of checksum's input data
+ * @checksum: offset where checksum is placed
+ */
+struct mt9e013_otp_checksum_format {
+ u16 start;
+ u16 end;
+ u16 checksum;
+};
+
+static const struct mt9e013_otp_checksum_format
+mt9e013_otp_checksum_list[] = {
+ {0x0004, 0x00d7, 0x00e1},
+ {0x00d8, 0x00df, 0x00e0},
+ {0x00e4, 0x01b7, 0x01c1},
+ {0x01b8, 0x01bf, 0x01c0},
+ {0x0000, 0x01c3, 0x01c4},
+};
+
+#define MAX_FMTS 1
+
+#define MT9E013_RES_WIDTH_MAX 3280
+#define MT9E013_RES_HEIGHT_MAX 2464
+
+/* Recommended Settings 29 Mar 2011*/
+static const struct mt9e013_reg mt9e013_recommended_settings[] = {
+ {MT9E013_16BIT, {0x3044}, 0x0590},
+ {MT9E013_16BIT, {0x306E}, 0xFC80},
+ {MT9E013_16BIT, {0x30B2}, 0xC000},
+ {MT9E013_16BIT, {0x30D6}, 0x0800},
+ {MT9E013_16BIT, {0x316C}, 0xB42F},
+ {MT9E013_16BIT, {0x316E}, 0x869A},
+ {MT9E013_16BIT, {0x3170}, 0x210E},
+ {MT9E013_16BIT, {0x317A}, 0x010E},
+ {MT9E013_16BIT, {0x31E0}, 0x1FB9},
+ {MT9E013_16BIT, {0x31E6}, 0x07FC},
+ {MT9E013_16BIT, {0x37C0}, 0x0000},
+ {MT9E013_16BIT, {0x37C2}, 0x0000},
+ {MT9E013_16BIT, {0x37C4}, 0x0000},
+ {MT9E013_16BIT, {0x37C6}, 0x0000},
+ {MT9E013_16BIT, {0x3E00}, 0x0011},
+ {MT9E013_16BIT, {0x3E02}, 0x8801},
+ {MT9E013_16BIT, {0x3E04}, 0x2801},
+ {MT9E013_16BIT, {0x3E06}, 0x8449},
+ {MT9E013_16BIT, {0x3E08}, 0x6841},
+ {MT9E013_16BIT, {0x3E0A}, 0x400C},
+ {MT9E013_16BIT, {0x3E0C}, 0x1001},
+ {MT9E013_16BIT, {0x3E0E}, 0x2603},
+ {MT9E013_16BIT, {0x3E10}, 0x4B41},
+ {MT9E013_16BIT, {0x3E12}, 0x4B24},
+ {MT9E013_16BIT, {0x3E14}, 0xA3CF},
+ {MT9E013_16BIT, {0x3E16}, 0x8802},
+ {MT9E013_16BIT, {0x3E18}, 0x84FF},
+ {MT9E013_16BIT, {0x3E1A}, 0x8601},
+ {MT9E013_16BIT, {0x3E1C}, 0x8401},
+ {MT9E013_16BIT, {0x3E1E}, 0x840A},
+ {MT9E013_16BIT, {0x3E20}, 0xFF00},
+ {MT9E013_16BIT, {0x3E22}, 0x8401},
+ {MT9E013_16BIT, {0x3E24}, 0x00FF},
+ {MT9E013_16BIT, {0x3E26}, 0x0088},
+ {MT9E013_16BIT, {0x3E28}, 0x2E8A},
+ {MT9E013_16BIT, {0x3E30}, 0x0000},
+ {MT9E013_16BIT, {0x3E32}, 0x8801},
+ {MT9E013_16BIT, {0x3E34}, 0x4029},
+ {MT9E013_16BIT, {0x3E36}, 0x00FF},
+ {MT9E013_16BIT, {0x3E38}, 0x8469},
+ {MT9E013_16BIT, {0x3E3A}, 0x00FF},
+ {MT9E013_16BIT, {0x3E3C}, 0x2801},
+ {MT9E013_16BIT, {0x3E3E}, 0x3E2A},
+ {MT9E013_16BIT, {0x3E40}, 0x1C01},
+ {MT9E013_16BIT, {0x3E42}, 0xFF84},
+ {MT9E013_16BIT, {0x3E44}, 0x8401},
+ {MT9E013_16BIT, {0x3E46}, 0x0C01},
+ {MT9E013_16BIT, {0x3E48}, 0x8401},
+ {MT9E013_16BIT, {0x3E4A}, 0x00FF},
+ {MT9E013_16BIT, {0x3E4C}, 0x8402},
+ {MT9E013_16BIT, {0x3E4E}, 0x8984},
+ {MT9E013_16BIT, {0x3E50}, 0x6628},
+ {MT9E013_16BIT, {0x3E52}, 0x8340},
+ {MT9E013_16BIT, {0x3E54}, 0x00FF},
+ {MT9E013_16BIT, {0x3E56}, 0x4A42},
+ {MT9E013_16BIT, {0x3E58}, 0x2703},
+ {MT9E013_16BIT, {0x3E5A}, 0x6752},
+ {MT9E013_16BIT, {0x3E5C}, 0x3F2A},
+ {MT9E013_16BIT, {0x3E5E}, 0x846A},
+ {MT9E013_16BIT, {0x3E60}, 0x4C01},
+ {MT9E013_16BIT, {0x3E62}, 0x8401},
+ {MT9E013_16BIT, {0x3E66}, 0x3901},
+ {MT9E013_16BIT, {0x3E90}, 0x2C01},
+ {MT9E013_16BIT, {0x3E98}, 0x2B02},
+ {MT9E013_16BIT, {0x3E92}, 0x2A04},
+ {MT9E013_16BIT, {0x3E94}, 0x2509},
+ {MT9E013_16BIT, {0x3E96}, 0x0000},
+ {MT9E013_16BIT, {0x3E9A}, 0x2905},
+ {MT9E013_16BIT, {0x3E9C}, 0x00FF},
+ {MT9E013_16BIT, {0x3ECC}, 0x00EB},
+ {MT9E013_16BIT, {0x3ED0}, 0x1E24},
+ {MT9E013_16BIT, {0x3ED4}, 0xAFC4},
+ {MT9E013_16BIT, {0x3ED6}, 0x909B},
+ {MT9E013_16BIT, {0x3EE0}, 0x2424},
+ {MT9E013_16BIT, {0x3EE2}, 0x9797},
+ {MT9E013_16BIT, {0x3EE4}, 0xC100},
+ {MT9E013_16BIT, {0x3EE6}, 0x0540},
+ {MT9E013_16BIT, {0x3174}, 0x8000},
+ {MT9E013_TOK_TERM, {0}, 0}
+};
+
+static const struct mt9e013_reg mt9e013_pll_timing[] = {
+ /* pixelrate into the isp = 153.600.000 Hz */
+ {MT9E013_16BIT, {0x0300}, 0x0004 }, /* vt_pix_clk_div= 4 internal pixel clock freq = 192.000.000 Hz */
+ {MT9E013_16BIT, {0x0302}, 0x0001 }, /* vt_sys_clk_div= 1 */
+ {MT9E013_16BIT, {0x0304}, 0x0002 }, /* pre_pll_clk_div= 2 PLL input clock freq = 9.600.000 Hz */
+ {MT9E013_16BIT, {0x0306}, 0x0050 }, /* pll_multiplier= 80 mipi bus speed = 768.000.000 Hz */
+ {MT9E013_16BIT, {0x0308}, 0x000A }, /* op_pix_clk_div= 10 output pixel clock freq = 76.800.000 Hz */
+ {MT9E013_16BIT, {0x030A}, 0x0001 }, /* op_sys_clk_div= 1 */
+ {MT9E013_16BIT, {0x3016}, 0x111 }, /* row_speed= 273 */
+ {MT9E013_TOK_DELAY, {0}, 1},
+ {MT9E013_TOK_TERM, {0}, 0}
+};
+
+
+/*2-lane MIPI Interface Configuration*/
+static const struct mt9e013_reg mt9e013_mipi_config[] = {
+ {MT9E013_16BIT+MT9E013_RMW, {0x3064}, 0x0100, 0x0000},
+ {MT9E013_16BIT, {0x31AE}, 0x0202},
+ {MT9E013_16BIT, {0x31B8}, 0x03EF},
+ /*{MT9E013_16BIT, {0x31B8}, 0x2FEF}, */
+ {MT9E013_TOK_DELAY, {0}, 5},
+ {MT9E013_TOK_TERM, {0}, 0}
+};
+
+/* MIPI Timing Settings */
+static const struct mt9e013_reg mt9e013_mipi_timing[] = {
+ {MT9E013_16BIT, {0x31B0}, 0x0083},
+ {MT9E013_16BIT, {0x31B2}, 0x004D},
+ {MT9E013_16BIT, {0x31B4}, 0x0E88},
+ {MT9E013_16BIT, {0x31B6}, 0x0D24},
+ {MT9E013_16BIT, {0x31B8}, 0x020E},
+ {MT9E013_16BIT, {0x31BA}, 0x0710},
+ {MT9E013_16BIT, {0x31BC}, 0x2A0D},
+ {MT9E013_16BIT, {0x31BE}, 0xC007},
+ {MT9E013_TOK_DELAY, {0}, 5},
+ {MT9E013_TOK_TERM, {0}, 0}
+};
+
+/* Start Streaming
+ * reset_register_restart_bad = 1
+ * reset_register_mask_bad = 1
+ * reset_register_lock_reg = 1
+ * grouped_parameter_hold = 0
+ * reset_register_stream = 1 */
+
+static const struct mt9e013_reg mt9e013_start_streaming[] = {
+ {MT9E013_16BIT+MT9E013_RMW, {0x301A}, 0x0200, 0x1},
+ {MT9E013_16BIT+MT9E013_RMW, {0x301A}, 0x0400, 0x1},
+ {MT9E013_16BIT+MT9E013_RMW, {0x301A}, 0x8, 0x1},
+ {MT9E013_16BIT, {0x0104}, 0x0},
+ {MT9E013_16BIT+MT9E013_RMW, {0x301A}, 0x4, 0x1},
+ {MT9E013_TOK_TERM, {0}, 0}
+};
+
+#define GROUPED_PARAMETER_HOLD_ENABLE {MT9E013_8BIT, {0x0104}, 0x1}
+
+#define GROUPED_PARAMETER_HOLD_DISABLE {MT9E013_8BIT, {0x0104}, 0x0}
+
+#define RESET_REGISTER {MT9E013_16BIT, {0x301A}, 0x4A18}
+
+#define INIT_VCM_CONTROL {MT9E013_16BIT, {0x30F0}, 0x8000}
+static const struct mt9e013_reg mt9e013_init_vcm[] = {
+ INIT_VCM_CONTROL, /* VCM_CONTROL */
+ {MT9E013_16BIT, {0x30F2}, 0x0000}, /* VCM_NEW_CODE */
+ {MT9E013_16BIT, {0x30F4}, 0x0000}, /* VCM_STEP_TIME */
+ {MT9E013_TOK_TERM, {0}, 0}
+};
+static const struct mt9e013_reg mt9e013_reset_register[] = {
+ {MT9E013_16BIT, {0x301A}, 0x10}, /* Lock_Register, transition to standby at frame end */
+ {MT9E013_TOK_TERM, {0}, 0}
+};
+
+static const struct mt9e013_reg mt9e013_raw_10[] = {
+ {MT9E013_16BIT, {0x0112}, 0x0A0A}, /* CCP_DATA_FORMAT, set to RAW10 mode */
+ {MT9E013_TOK_TERM, {0}, 0}
+};
+
+static const struct mt9e013_reg mt9e013_scaler[] = {
+ {MT9E013_16BIT, {0x0400}, 0x0000}, /* SCALE_MODE: 0:disable */
+ {MT9E013_16BIT, {0x0404}, 0x0010}, /* SCALE_M = 16 */
+ {MT9E013_TOK_TERM, {0}, 0}
+};
+
+/*****************************************************************************/
+/*****************************************************************************/
+/*****************************************************************************/
+
+/*****************************still15ok*****************************/
+static struct mt9e013_reg const mt9e013_STILL_8M_12fps[] = {
+ /* STILL 8M */
+ GROUPED_PARAMETER_HOLD_ENABLE,
+ /* Output size */
+ {MT9E013_16BIT, {0x0344}, 0x0000 }, /* X_ADDR_START 0 */
+ {MT9E013_16BIT, {0x0348}, 0x0CCF }, /* X_ADDR_END 3279 */
+ {MT9E013_16BIT, {0x0346}, 0x0000 }, /* Y_ADDR_START 0 */
+ {MT9E013_16BIT, {0x034A}, 0x099F }, /* Y_ADDR_END 2463 */
+ {MT9E013_16BIT, {0x034C}, 0x0CD0 }, /* X_OUTPUT_SIZE 3280 */
+ {MT9E013_16BIT, {0x034E}, 0x09A0 }, /* Y_OUTPUT_SIZE 2464 */
+ {MT9E013_16BIT, {0x3040}, 0x0041 }, /* READ_MODE 65 */
+ /* Timing Configuation */
+ {MT9E013_16BIT, {0x0342}, 0x17F8 }, /* line_length_pck 6136 */
+ {MT9E013_16BIT, {0x0340}, 0x0A2F }, /* frame_length_lines 2607 */
+ {MT9E013_16BIT, {0x0202}, 0x0A2F }, /* COARSE_INTEGRATION_TIME 2607 */
+ {MT9E013_16BIT, {0x3014}, 0x0D77 }, /* FINE_INTEGRATION_TIME 3348 */
+ {MT9E013_16BIT, {0x3010}, 0x0078 }, /* FINE_CORRECTION 120 */
+ /* scaler */
+ {MT9E013_16BIT, {0x0400}, 0x0 }, /* SCALE_MODE 0 */
+ {MT9E013_16BIT, {0x0404}, 0x10 }, /* SCALE_M 16 */
+ {MT9E013_TOK_TERM, {0}, 0}
+};
+
+static struct mt9e013_reg const mt9e013_STILL_6M_15fps[] = {
+ /* STILL 6M */
+ GROUPED_PARAMETER_HOLD_ENABLE,
+ /* Output size */
+ {MT9E013_16BIT, {0x0344}, 0x0000 }, /* X_ADDR_START 0 */
+ {MT9E013_16BIT, {0x0348}, 0x0CCF }, /* X_ADDR_END 3279 */
+ {MT9E013_16BIT, {0x0346}, 0x0134 }, /* Y_ADDR_START 308 */
+ {MT9E013_16BIT, {0x034A}, 0x086D }, /* Y_ADDR_END 2157 */
+ {MT9E013_16BIT, {0x034C}, 0x0CD0 }, /* X_OUTPUT_SIZE 3280 */
+ {MT9E013_16BIT, {0x034E}, 0x0738 }, /* Y_OUTPUT_SIZE 1848 */
+ {MT9E013_16BIT, {0x3040}, 0x0041 }, /* READ_MODE 65 */
+ /* Timing Configuation */
+ {MT9E013_16BIT, {0x0342}, 0x191C }, /* line_length_pck 6428 */
+ {MT9E013_16BIT, {0x0340}, 0x07C7 }, /* frame_length_lines 1991 */
+ {MT9E013_16BIT, {0x0202}, 0x07C7 }, /* COARSE_INTEGRATION_TIME 1991 */
+ {MT9E013_16BIT, {0x3014}, 0x073C }, /* FINE_INTEGRATION_TIME 1852 */
+ {MT9E013_16BIT, {0x3010}, 0x0078 }, /* FINE_CORRECTION 120 */
+ /* scaler */
+ {MT9E013_16BIT, {0x0400}, 0x0 }, /* SCALE_MODE 0 */
+ {MT9E013_16BIT, {0x0404}, 0x10 }, /* SCALE_M 16 */
+ {MT9E013_TOK_TERM, {0}, 0}
+};
+
+static struct mt9e013_reg const mt9e013_STILL_2M_15fps[] = {
+ /* STILL 2M */
+ GROUPED_PARAMETER_HOLD_ENABLE,
+ /* Output size */
+ {MT9E013_16BIT, {0x0344}, 0x0000 }, /* X_ADDR_START 0 */
+ {MT9E013_16BIT, {0x0348}, 0x0CD1 }, /* X_ADDR_END 3281 */
+ {MT9E013_16BIT, {0x0346}, 0x0000 }, /* Y_ADDR_START 0 */
+ {MT9E013_16BIT, {0x034A}, 0x09A1 }, /* Y_ADDR_END 2465 */
+ {MT9E013_16BIT, {0x034C}, 0x0668 }, /* X_OUTPUT_SIZE 1640 */
+ {MT9E013_16BIT, {0x034E}, 0x04D0 }, /* Y_OUTPUT_SIZE 1232 */
+ {MT9E013_16BIT, {0x3040}, 0x04C3 }, /* READ_MODE 1219 */
+ /* Timing Configuation */
+ {MT9E013_16BIT, {0x0342}, 0x2460 }, /* line_length_pck 9312 */
+ {MT9E013_16BIT, {0x0340}, 0x0563 }, /* frame_length_lines 1379 */
+ {MT9E013_16BIT, {0x0202}, 0x055F }, /* COARSE_INTEGRATION_TIME 1375 */
+ {MT9E013_16BIT, {0x3014}, 0x0846 }, /* FINE_INTEGRATION_TIME 2118 */
+ {MT9E013_16BIT, {0x3010}, 0x0130 }, /* FINE_CORRECTION 304 */
+ /* scaler */
+ {MT9E013_16BIT, {0x0400}, 0x0 }, /* SCALE_MODE 0 */
+ {MT9E013_16BIT, {0x0404}, 0x10 }, /* SCALE_M 16 */
+ {MT9E013_TOK_TERM, {0}, 0}
+};
+
+/*****************************preview30ok********************************/
+static struct mt9e013_reg const mt9e013_PREVIEW_30fps[] = {
+ /* PREVIEW */
+ GROUPED_PARAMETER_HOLD_ENABLE,
+ /* Output size */
+ {MT9E013_16BIT, {0x0344}, 0x0000 }, /* X_ADDR_START 0 */
+ {MT9E013_16BIT, {0x0348}, 0x0CC9 }, /* X_ADDR_END 3273 */
+ {MT9E013_16BIT, {0x0346}, 0x0000 }, /* Y_ADDR_START 0 */
+ {MT9E013_16BIT, {0x034A}, 0x0999 }, /* Y_ADDR_END 2457 */
+ {MT9E013_16BIT, {0x034C}, 0x0334 }, /* X_OUTPUT_SIZE 820 */
+ {MT9E013_16BIT, {0x034E}, 0x0268 }, /* Y_OUTPUT_SIZE 616 */
+ {MT9E013_16BIT, {0x3040}, 0x05C7 }, /* READ_MODE 5575 */
+ /* Timing Configuation */
+ {MT9E013_16BIT, {0x0342}, 0x20F0 }, /* line_length_pck 8432 */
+ {MT9E013_16BIT, {0x0340}, 0x02F7 }, /* frame_length_lines 759 */
+ {MT9E013_16BIT, {0x0202}, 0x02F7 }, /* COARSE_INTEGRATION_TIME 759 */
+ {MT9E013_16BIT, {0x3014}, 0x0846 }, /* FINE_INTEGRATION_TIME 2118 */
+ {MT9E013_16BIT, {0x3010}, 0x0130 }, /* FINE_CORRECTION 304 */
+ /* scaler */
+ {MT9E013_16BIT, {0x0400}, 0x0 }, /* SCALE_MODE 0 */
+ {MT9E013_16BIT, {0x0404}, 0x10 }, /* SCALE_M 16 */
+ {MT9E013_TOK_TERM, {0}, 0}
+};
+
+static struct mt9e013_reg const mt9e013_WIDE_PREVIEW_30fps[] = {
+ /* WIDE PREVIEW */
+ GROUPED_PARAMETER_HOLD_ENABLE,
+ /* Output size */
+ {MT9E013_16BIT, {0x0344}, 0x0000 }, /* X_ADDR_START 0 */
+ {MT9E013_16BIT, {0x0348}, 0x0CD1 }, /* X_ADDR_END 3281 */
+ {MT9E013_16BIT, {0x0346}, 0x0114 }, /* Y_ADDR_START 276 */
+ {MT9E013_16BIT, {0x034A}, 0x088D }, /* Y_ADDR_END 2189 */
+ {MT9E013_16BIT, {0x034C}, 0x0668 }, /* X_OUTPUT_SIZE 1640 */
+ {MT9E013_16BIT, {0x034E}, 0x03BC }, /* Y_OUTPUT_SIZE 956 */
+ {MT9E013_16BIT, {0x3040}, 0x04C3 }, /* READ_MODE 1219 */
+ /* Timing Configuation */
+ {MT9E013_16BIT, {0x0342}, 0x16C2 }, /* line_length_pck 5826 */
+ {MT9E013_16BIT, {0x0340}, 0x044F }, /* frame_length_lines 1103 */
+ {MT9E013_16BIT, {0x0202}, 0x044B }, /* COARSE_INTEGRATION_TIME 1099 */
+ {MT9E013_16BIT, {0x3014}, 0x0846 }, /* FINE_INTEGRATION_TIME 2118 */
+ {MT9E013_16BIT, {0x3010}, 0x0130 }, /* FINE_CORRECTION 304 */
+ /* scaler */
+ {MT9E013_16BIT, {0x0400}, 0x0 }, /* SCALE_MODE 0 */
+ {MT9E013_16BIT, {0x0404}, 0x10 }, /* SCALE_M 16 */
+ {MT9E013_TOK_TERM, {0}, 0}
+};
+
+/*****************************video************************/
+static struct mt9e013_reg const mt9e013_1080p_strong_dvs_30fps[] = {
+ /* 1080p strong dvs */
+ GROUPED_PARAMETER_HOLD_ENABLE,
+ /* Output size */
+ {MT9E013_16BIT, {0x0344}, 0x01D8 }, /* X_ADDR_START 472 */
+ {MT9E013_16BIT, {0x0348}, 0x0AF7 }, /* X_ADDR_END 2807 */
+ {MT9E013_16BIT, {0x0346}, 0x0242 }, /* Y_ADDR_START 578 */
+ {MT9E013_16BIT, {0x034A}, 0x075D }, /* Y_ADDR_END 1885 */
+ {MT9E013_16BIT, {0x034C}, 0x0920 }, /* X_OUTPUT_SIZE 2336 */
+ {MT9E013_16BIT, {0x034E}, 0x051C }, /* Y_OUTPUT_SIZE 1308 */
+ {MT9E013_16BIT, {0x3040}, 0x0041 }, /* READ_MODE 65 */
+ /* Timing Configuation */
+ {MT9E013_16BIT, {0x0342}, 0x113A }, /* line_length_pck 4410 */
+ {MT9E013_16BIT, {0x0340}, 0x05AB }, /* frame_length_lines 1451 */
+ {MT9E013_16BIT, {0x0202}, 0x05AB }, /* COARSE_INTEGRATION_TIME 1451 */
+ {MT9E013_16BIT, {0x3014}, 0x0442 }, /* FINE_INTEGRATION_TIME 1090 */
+ {MT9E013_16BIT, {0x3010}, 0x0078 }, /* FINE_CORRECTION 120 */
+ /* scaler */
+ {MT9E013_16BIT, {0x0400}, 0x0 }, /* SCALE_MODE 0 */
+ {MT9E013_16BIT, {0x0404}, 0x10 }, /* SCALE_M 16 */
+ {MT9E013_TOK_TERM, {0}, 0}
+};
+
+static struct mt9e013_reg const mt9e013_720p_strong_dvs_30fps[] = {
+ /* 720p strong dvs */
+ GROUPED_PARAMETER_HOLD_ENABLE,
+ /* Output size */
+ {MT9E013_16BIT, {0x0344}, 0x0048 }, /* X_ADDR_START 72 */
+ {MT9E013_16BIT, {0x0348}, 0x0C89 }, /* X_ADDR_END 3209 */
+ {MT9E013_16BIT, {0x0346}, 0x0164 }, /* Y_ADDR_START 356 */
+ {MT9E013_16BIT, {0x034A}, 0x083D }, /* Y_ADDR_END 2109 */
+ {MT9E013_16BIT, {0x034C}, 0x0620 }, /* X_OUTPUT_SIZE 1568 */
+ {MT9E013_16BIT, {0x034E}, 0x036C }, /* Y_OUTPUT_SIZE 876 */
+ {MT9E013_16BIT, {0x3040}, 0x04C3 }, /* READ_MODE 5315 */
+ /* Timing Configuation */
+ {MT9E013_16BIT, {0x0342}, 0x188C }, /* line_length_pck 6284 */
+ {MT9E013_16BIT, {0x0340}, 0x03FF }, /* frame_length_lines 1023 */
+ {MT9E013_16BIT, {0x0202}, 0x03FB }, /* COARSE_INTEGRATION_TIME 1019 */
+ {MT9E013_16BIT, {0x3014}, 0x0846 }, /* FINE_INTEGRATION_TIME 2118 */
+ {MT9E013_16BIT, {0x3010}, 0x0130 }, /* FINE_CORRECTION 304 */
+ /* scaler */
+ {MT9E013_16BIT, {0x0400}, 0x2 }, /* SCALE_MODE 2 */
+ {MT9E013_16BIT, {0x0404}, 0x10 }, /* SCALE_M 16 */
+ {MT9E013_TOK_TERM, {0}, 0}
+};
+
+static struct mt9e013_reg const mt9e013_WVGA_strong_dvs_30fps[] = {
+ /* WVGA strong dvs */
+ GROUPED_PARAMETER_HOLD_ENABLE,
+ /* Output size */
+ {MT9E013_16BIT, {0x0344}, 0x0000 }, /* X_ADDR_START 0 */
+ {MT9E013_16BIT, {0x0348}, 0x0CCD }, /* X_ADDR_END 3281 */
+ {MT9E013_16BIT, {0x0346}, 0x00D0 }, /* Y_ADDR_START 208 */
+ {MT9E013_16BIT, {0x034A}, 0x08CD }, /* Y_ADDR_END 2253 */
+ {MT9E013_16BIT, {0x034C}, 0x0668 }, /* X_OUTPUT_SIZE 1640 */
+ {MT9E013_16BIT, {0x034E}, 0x0400 }, /* Y_OUTPUT_SIZE 1024 */
+ {MT9E013_16BIT, {0x3040}, 0x04C3 }, /* READ_MODE 195 */
+ /* Timing Configuation */
+ {MT9E013_16BIT, {0x0342}, 0x156C }, /* line_length_pck 5484 */
+ {MT9E013_16BIT, {0x0340}, 0x048F }, /* frame_length_lines 1167 */
+ {MT9E013_16BIT, {0x0202}, 0x048F }, /* COARSE_INTEGRATION_TIME 1167 */
+ {MT9E013_16BIT, {0x3014}, 0x0846 }, /* FINE_INTEGRATION_TIME 2118 */
+ {MT9E013_16BIT, {0x3010}, 0x0130 }, /* FINE_CORRECTION 304 */
+ /* scaler */
+ {MT9E013_16BIT, {0x0400}, 0x0 }, /* SCALE_MODE 0 */
+ {MT9E013_16BIT, {0x0404}, 0x10 }, /* SCALE_M 16 */
+ {MT9E013_TOK_TERM, {0}, 0}
+};
+
+static struct mt9e013_reg const mt9e013_VGA_strong_dvs_30fps[] = {
+ /* VGA strong dvs */
+ GROUPED_PARAMETER_HOLD_ENABLE,
+ /* Output size */
+ {MT9E013_16BIT, {0x0344}, 0x0000 }, /* X_ADDR_START 0 */
+ {MT9E013_16BIT, {0x0348}, 0x0CC9 }, /* X_ADDR_END 3273 */
+ {MT9E013_16BIT, {0x0346}, 0x0000 }, /* Y_ADDR_START 0 */
+ {MT9E013_16BIT, {0x034A}, 0x0999 }, /* Y_ADDR_END 2457 */
+ {MT9E013_16BIT, {0x034C}, 0x0334 }, /* X_OUTPUT_SIZE 820 */
+ {MT9E013_16BIT, {0x034E}, 0x0268 }, /* Y_OUTPUT_SIZE 616 */
+ {MT9E013_16BIT, {0x3040}, 0x05C7 }, /* READ_MODE 1479 */
+ /* Timing Configuation */
+ {MT9E013_16BIT, {0x0342}, 0x20F0 }, /* line_length_pck 8432 */
+ {MT9E013_16BIT, {0x0340}, 0x02F7 }, /* frame_length_lines 759 */
+ {MT9E013_16BIT, {0x0202}, 0x02F7 }, /* COARSE_INTEGRATION_TIME 759 */
+ {MT9E013_16BIT, {0x3014}, 0x0846 }, /* FINE_INTEGRATION_TIME 2118 */
+ {MT9E013_16BIT, {0x3010}, 0x0130 }, /* FINE_CORRECTION 304 */
+ /* scaler */
+ {MT9E013_16BIT, {0x0400}, 0x0 }, /* SCALE_MODE 0 */
+ {MT9E013_16BIT, {0x0404}, 0x10 }, /* SCALE_M 16 */
+ {MT9E013_TOK_TERM, {0}, 0}
+};
+
+#if 0
+static struct mt9e013_reg const mt9e013_QVGA_strong_dvs_30fps[] = {
+ /* QVGA strong dvs */
+ GROUPED_PARAMETER_HOLD_ENABLE,
+ /* Output size */
+ {MT9E013_16BIT, {0x0344}, 0x0000 }, /* X_ADDR_START 0 */
+ {MT9E013_16BIT, {0x0348}, 0x0CC9 }, /* X_ADDR_END 3273 */
+ {MT9E013_16BIT, {0x0346}, 0x0000 }, /* Y_ADDR_START 0 */
+ {MT9E013_16BIT, {0x034A}, 0x0999 }, /* Y_ADDR_END 2457 */
+ {MT9E013_16BIT, {0x034C}, 0x019A }, /* X_OUTPUT_SIZE 410 */
+ {MT9E013_16BIT, {0x034E}, 0x0134 }, /* Y_OUTPUT_SIZE 308 */
+ {MT9E013_16BIT, {0x3040}, 0x05C7 }, /* READ_MODE 1479 */
+ /* Timing Configuation */
+ {MT9E013_16BIT, {0x0342}, 0x20F0 }, /* line_length_pck 8432 */
+ {MT9E013_16BIT, {0x0340}, 0x02F7 }, /* frame_length_lines 759 */
+ {MT9E013_16BIT, {0x0202}, 0x02F7 }, /* COARSE_INTEGRATION_TIME 759 */
+ {MT9E013_16BIT, {0x3014}, 0x0846 }, /* FINE_INTEGRATION_TIME 2118 */
+ {MT9E013_16BIT, {0x3010}, 0x0130 }, /* FINE_CORRECTION 304 */
+ /* scaler */
+ {MT9E013_16BIT, {0x0400}, 0x2 }, /* SCALE_MODE 0 */
+ {MT9E013_16BIT, {0x0404}, 0x20 }, /* SCALE_M 32 */
+ {MT9E013_TOK_TERM, {0}, 0}
+};
+
+
+static struct mt9e013_reg const mt9e013_QCIF_strong_dvs_30fps[] = {
+ /* QCIF strong dvs */
+ GROUPED_PARAMETER_HOLD_ENABLE,
+ /* Output size */
+ {MT9E013_16BIT, {0x0344}, 0x0000 }, /* X_ADDR_START 0 */
+ {MT9E013_16BIT, {0x0348}, 0x0CC9 }, /* X_ADDR_END 3273 */
+ {MT9E013_16BIT, {0x0346}, 0x0000 }, /* Y_ADDR_START 0 */
+ {MT9E013_16BIT, {0x034A}, 0x0999 }, /* Y_ADDR_END 2457 */
+ {MT9E013_16BIT, {0x034C}, 0x019A }, /* X_OUTPUT_SIZE 205 */
+ {MT9E013_16BIT, {0x034E}, 0x0134 }, /* Y_OUTPUT_SIZE 154 */
+ {MT9E013_16BIT, {0x3040}, 0x05C7 }, /* READ_MODE 1479 */
+ /* Timing Configuation */
+ {MT9E013_16BIT, {0x0342}, 0x20F0 }, /* line_length_pck 8432 */
+ {MT9E013_16BIT, {0x0340}, 0x02F7 }, /* frame_length_lines 759 */
+ {MT9E013_16BIT, {0x0202}, 0x02F7 }, /* COARSE_INTEGRATION_TIME 759 */
+ {MT9E013_16BIT, {0x3014}, 0x0846 }, /* FINE_INTEGRATION_TIME 2118 */
+ {MT9E013_16BIT, {0x3010}, 0x0130 }, /* FINE_CORRECTION 304 */
+ /* scaler */
+ {MT9E013_16BIT, {0x0400}, 0x2 }, /* SCALE_MODE 0 */
+ {MT9E013_16BIT, {0x0404}, 0x40 }, /* SCALE_M 64 */
+ {MT9E013_TOK_TERM, {0}, 0}
+};
+#endif
+
+static struct mt9e013_reg const mt9e013_QVGA_strong_dvs_30fps[] = {
+ /* QVGA strong dvs */
+ GROUPED_PARAMETER_HOLD_ENABLE,
+ /* Output size */
+ {MT9E013_16BIT, {0x0344}, 0x0368 }, /* X_ADDR_START 872 */
+ {MT9E013_16BIT, {0x0348}, 0x0961 }, /* X_ADDR_END 2401 */
+ {MT9E013_16BIT, {0x0346}, 0x0290 }, /* Y_ADDR_START 656 */
+ {MT9E013_16BIT, {0x034A}, 0x0709 }, /* Y_ADDR_END 1801 */
+ {MT9E013_16BIT, {0x034C}, 0x0180 }, /* X_OUTPUT_SIZE 384 */
+ {MT9E013_16BIT, {0x034E}, 0x0120 }, /* Y_OUTPUT_SIZE 288 */
+ {MT9E013_16BIT, {0x3040}, 0x05C7 }, /* READ_MODE 1479 */
+ /* Timing Configuation */
+ {MT9E013_16BIT, {0x0342}, 0x3A00 }, /* line_length_pck 14848 */
+ {MT9E013_16BIT, {0x0340}, 0x01AF }, /* frame_length_lines 431 */
+ {MT9E013_16BIT, {0x0202}, 0x01AF }, /* COARSE_INTEGRATION_TIME 431 */
+ {MT9E013_16BIT, {0x3014}, 0x0846 }, /* FINE_INTEGRATION_TIME 2118 */
+ {MT9E013_16BIT, {0x3010}, 0x0130 }, /* FINE_CORRECTION 304 */
+ /* scaler */
+ {MT9E013_16BIT, {0x0400}, 0x0 }, /* SCALE_MODE 0 */
+ {MT9E013_16BIT, {0x0404}, 0x40 }, /* SCALE_M 16 */
+ {MT9E013_TOK_TERM, {0}, 0}
+};
+
+static struct mt9e013_reg const mt9e013_QCIF_strong_dvs_30fps[] = {
+ /* QCIF strong dvs */
+ GROUPED_PARAMETER_HOLD_ENABLE,
+ /* Output size */
+ {MT9E013_16BIT, {0x0344}, 0x0368 }, /* X_ADDR_START 872 */
+ {MT9E013_16BIT, {0x0348}, 0x0961 }, /* X_ADDR_END 2401 */
+ {MT9E013_16BIT, {0x0346}, 0x0288 }, /* Y_ADDR_START 648 */
+ {MT9E013_16BIT, {0x034A}, 0x0711 }, /* Y_ADDR_END 1809 */
+ {MT9E013_16BIT, {0x034C}, 0x0180 }, /* X_OUTPUT_SIZE 384 */
+ {MT9E013_16BIT, {0x034E}, 0x0124 }, /* Y_OUTPUT_SIZE 292 */
+ {MT9E013_16BIT, {0x3040}, 0x05C7 }, /* READ_MODE 1479 */
+ /* Timing Configuation */
+ {MT9E013_16BIT, {0x0342}, 0x3978 }, /* line_length_pck 14712 */
+ {MT9E013_16BIT, {0x0340}, 0x01B3 }, /* frame_length_lines 435 */
+ {MT9E013_16BIT, {0x0202}, 0x01B3 }, /* COARSE_INTEGRATION_TIME 435 */
+ {MT9E013_16BIT, {0x3014}, 0x0846 }, /* FINE_INTEGRATION_TIME 2118 */
+ {MT9E013_16BIT, {0x3010}, 0x0130 }, /* FINE_CORRECTION 304 */
+ /* scaler */
+ {MT9E013_16BIT, {0x0400}, 0x0 }, /* SCALE_MODE 0 */
+ {MT9E013_16BIT, {0x0404}, 0x10 }, /* SCALE_M 16 */
+ {MT9E013_TOK_TERM, {0}, 0}
+};
+
+
+
+/*****************************************************************************/
+/*****************************************************************************/
+/*****************************************************************************/
+
+static const struct mt9e013_reg mt9e013_soft_standby[] = {
+ {MT9E013_8BIT, {0x301C}, 0x00},
+ {MT9E013_TOK_TERM, {0}, 0}
+};
+
+static const struct mt9e013_reg mt9e013_streaming[] = {
+ {MT9E013_8BIT, {0x301C}, 0x01},
+ {MT9E013_TOK_TERM, {0}, 0}
+};
+
+static const struct mt9e013_reg mt9e013_param_hold[] = {
+ {MT9E013_8BIT, {0x0104}, 0x01}, /* GROUPED_PARAMETER_HOLD */
+ {MT9E013_TOK_TERM, {0}, 0}
+};
+
+static const struct mt9e013_reg mt9e013_param_update[] = {
+ {MT9E013_8BIT, {0x0104}, 0x00}, /* GROUPED_PARAMETER_HOLD */
+ {MT9E013_TOK_TERM, {0}, 0}
+};
+
+static const struct mt9e013_reg mt9e013_lens_shading[] = {
+ {MT9E013_16BIT | MT9E013_RMW, {0x3780}, 0x8000, 0}, /* POLY_SC_ENABLE */
+ {MT9E013_16BIT, {0x3600}, 0x0430}, /* P_GR_P0Q0 */
+ {MT9E013_16BIT, {0x3602}, 0x1BEE}, /* P_GR_P0Q1 */
+ {MT9E013_16BIT, {0x3604}, 0x39F0}, /* P_GR_P0Q2 */
+ {MT9E013_16BIT, {0x3606}, 0xC7AD}, /* P_GR_P0Q3 */
+ {MT9E013_16BIT, {0x3608}, 0xC390}, /* P_GR_P0Q4 */
+ {MT9E013_16BIT, {0x360A}, 0x03D0}, /* P_RD_P0Q0 */
+ {MT9E013_16BIT, {0x360C}, 0xA0CE}, /* P_RD_P0Q1 */
+ {MT9E013_16BIT, {0x360E}, 0x2850}, /* P_RD_P0Q2 */
+ {MT9E013_16BIT, {0x3610}, 0x6A0E}, /* P_RD_P0Q3 */
+ {MT9E013_16BIT, {0x3612}, 0xAF30}, /* P_RD_P0Q4 */
+ {MT9E013_16BIT, {0x3614}, 0x03D0}, /* P_BL_P0Q0 */
+ {MT9E013_16BIT, {0x3616}, 0x36AE}, /* P_BL_P0Q1 */
+ {MT9E013_16BIT, {0x3618}, 0x5E6F}, /* P_BL_P0Q2 */
+ {MT9E013_16BIT, {0x361A}, 0xA22E}, /* P_BL_P0Q3 */
+ {MT9E013_16BIT, {0x361C}, 0xF6EF}, /* P_BL_P0Q4 */
+ {MT9E013_16BIT, {0x361E}, 0x02F0}, /* P_GB_P0Q0 */
+ {MT9E013_16BIT, {0x3620}, 0xA00E}, /* P_GB_P0Q1 */
+ {MT9E013_16BIT, {0x3622}, 0x3CD0}, /* P_GB_P0Q2 */
+ {MT9E013_16BIT, {0x3624}, 0x530E}, /* P_GB_P0Q3 */
+ {MT9E013_16BIT, {0x3626}, 0xCEF0}, /* P_GB_P0Q4 */
+ {MT9E013_16BIT, {0x3640}, 0xAB2D}, /* P_GR_P1Q0 */
+ {MT9E013_16BIT, {0x3642}, 0xB72E}, /* P_GR_P1Q1 */
+ {MT9E013_16BIT, {0x3644}, 0x988D}, /* P_GR_P1Q2 */
+ {MT9E013_16BIT, {0x3646}, 0x6E2E}, /* P_GR_P1Q3 */
+ {MT9E013_16BIT, {0x3648}, 0x53EE}, /* P_GR_P1Q4 */
+ {MT9E013_16BIT, {0x364A}, 0xDA2C}, /* P_RD_P1Q0 */
+ {MT9E013_16BIT, {0x364C}, 0x3E8D}, /* P_RD_P1Q1 */
+ {MT9E013_16BIT, {0x364E}, 0xAFAD}, /* P_RD_P1Q2 */
+ {MT9E013_16BIT, {0x3650}, 0x874E}, /* P_RD_P1Q3 */
+ {MT9E013_16BIT, {0x3652}, 0x5B4E}, /* P_RD_P1Q4 */
+ {MT9E013_16BIT, {0x3654}, 0x740D}, /* P_BL_P1Q0 */
+ {MT9E013_16BIT, {0x3656}, 0x310E}, /* P_BL_P1Q1 */
+ {MT9E013_16BIT, {0x3658}, 0x280B}, /* P_BL_P1Q2 */
+ {MT9E013_16BIT, {0x365A}, 0xE06E}, /* P_BL_P1Q3 */
+ {MT9E013_16BIT, {0x365C}, 0xEA0D}, /* P_BL_P1Q4 */
+ {MT9E013_16BIT, {0x365E}, 0x182D}, /* P_GB_P1Q0 */
+ {MT9E013_16BIT, {0x3660}, 0xAD0E}, /* P_GB_P1Q1 */
+ {MT9E013_16BIT, {0x3662}, 0x032E}, /* P_GB_P1Q2 */
+ {MT9E013_16BIT, {0x3664}, 0x7EEE}, /* P_GB_P1Q3 */
+ {MT9E013_16BIT, {0x3666}, 0xF34E}, /* P_GB_P1Q4 */
+ {MT9E013_16BIT, {0x3680}, 0x0E31}, /* P_GR_P2Q0 */
+ {MT9E013_16BIT, {0x3682}, 0x104F}, /* P_GR_P2Q1 */
+ {MT9E013_16BIT, {0x3684}, 0x92D3}, /* P_GR_P2Q2 */
+ {MT9E013_16BIT, {0x3686}, 0xA030}, /* P_GR_P2Q3 */
+ {MT9E013_16BIT, {0x3688}, 0x3873}, /* P_GR_P2Q4 */
+ {MT9E013_16BIT, {0x368A}, 0x1971}, /* P_RD_P2Q0 */
+ {MT9E013_16BIT, {0x368C}, 0x750C}, /* P_RD_P2Q1 */
+ {MT9E013_16BIT, {0x368E}, 0xFFF2}, /* P_RD_P2Q2 */
+ {MT9E013_16BIT, {0x3690}, 0xEDAF}, /* P_RD_P2Q3 */
+ {MT9E013_16BIT, {0x3692}, 0x1D73}, /* P_RD_P2Q4 */
+ {MT9E013_16BIT, {0x3694}, 0x0031}, /* P_BL_P2Q0 */
+ {MT9E013_16BIT, {0x3696}, 0x1A2F}, /* P_BL_P2Q1 */
+ {MT9E013_16BIT, {0x3698}, 0xF792}, /* P_BL_P2Q2 */
+ {MT9E013_16BIT, {0x369A}, 0x8530}, /* P_BL_P2Q3 */
+ {MT9E013_16BIT, {0x369C}, 0x1F73}, /* P_BL_P2Q4 */
+ {MT9E013_16BIT, {0x369E}, 0x08B1}, /* P_GB_P2Q0 */
+ {MT9E013_16BIT, {0x36A0}, 0x11AE}, /* P_GB_P2Q1 */
+ {MT9E013_16BIT, {0x36A2}, 0x9093}, /* P_GB_P2Q2 */
+ {MT9E013_16BIT, {0x36A4}, 0x9030}, /* P_GB_P2Q3 */
+ {MT9E013_16BIT, {0x36A6}, 0x36D3}, /* P_GB_P2Q4 */
+ {MT9E013_16BIT, {0x36C0}, 0x5F2D}, /* P_GR_P3Q0 */
+ {MT9E013_16BIT, {0x36C2}, 0x314F}, /* P_GR_P3Q1 */
+ {MT9E013_16BIT, {0x36C4}, 0x684E}, /* P_GR_P3Q2 */
+ {MT9E013_16BIT, {0x36C6}, 0x88B0}, /* P_GR_P3Q3 */
+ {MT9E013_16BIT, {0x36C8}, 0xDAF0}, /* P_GR_P3Q4 */
+ {MT9E013_16BIT, {0x36CA}, 0x636E}, /* P_RD_P3Q0 */
+ {MT9E013_16BIT, {0x36CC}, 0xAD0C}, /* P_RD_P3Q1 */
+ {MT9E013_16BIT, {0x36CE}, 0xEEEE}, /* P_RD_P3Q2 */
+ {MT9E013_16BIT, {0x36D0}, 0x500E}, /* P_RD_P3Q3 */
+ {MT9E013_16BIT, {0x36D2}, 0xDDCE}, /* P_RD_P3Q4 */
+ {MT9E013_16BIT, {0x36D4}, 0xA3AC}, /* P_BL_P3Q0 */
+ {MT9E013_16BIT, {0x36D6}, 0xC06E}, /* P_BL_P3Q1 */
+ {MT9E013_16BIT, {0x36D8}, 0xC04F}, /* P_BL_P3Q2 */
+ {MT9E013_16BIT, {0x36DA}, 0x49AF}, /* P_BL_P3Q3 */
+ {MT9E013_16BIT, {0x36DC}, 0x4830}, /* P_BL_P3Q4 */
+ {MT9E013_16BIT, {0x36DE}, 0x0F6B}, /* P_GB_P3Q0 */
+ {MT9E013_16BIT, {0x36E0}, 0x1DEF}, /* P_GB_P3Q1 */
+ {MT9E013_16BIT, {0x36E2}, 0x8730}, /* P_GB_P3Q2 */
+ {MT9E013_16BIT, {0x36E4}, 0x9E50}, /* P_GB_P3Q3 */
+ {MT9E013_16BIT, {0x36E6}, 0x7110}, /* P_GB_P3Q4 */
+ {MT9E013_16BIT, {0x3700}, 0xF4F1}, /* P_GR_P4Q0 */
+ {MT9E013_16BIT, {0x3702}, 0xF090}, /* P_GR_P4Q1 */
+ {MT9E013_16BIT, {0x3704}, 0x6493}, /* P_GR_P4Q2 */
+ {MT9E013_16BIT, {0x3706}, 0x5FB1}, /* P_GR_P4Q3 */
+ {MT9E013_16BIT, {0x3708}, 0xADB3}, /* P_GR_P4Q4 */
+ {MT9E013_16BIT, {0x370A}, 0xFEF1}, /* P_RD_P4Q0 */
+ {MT9E013_16BIT, {0x370C}, 0x134B}, /* P_RD_P4Q1 */
+ {MT9E013_16BIT, {0x370E}, 0x4D33}, /* P_RD_P4Q2 */
+ {MT9E013_16BIT, {0x3710}, 0x9B8E}, /* P_RD_P4Q3 */
+ {MT9E013_16BIT, {0x3712}, 0x88B3}, /* P_RD_P4Q4 */
+ {MT9E013_16BIT, {0x3714}, 0xEBB1}, /* P_BL_P4Q0 */
+ {MT9E013_16BIT, {0x3716}, 0x8131}, /* P_BL_P4Q1 */
+ {MT9E013_16BIT, {0x3718}, 0x5AD3}, /* P_BL_P4Q2 */
+ {MT9E013_16BIT, {0x371A}, 0x54F1}, /* P_BL_P4Q3 */
+ {MT9E013_16BIT, {0x371C}, 0xB193}, /* P_BL_P4Q4 */
+ {MT9E013_16BIT, {0x371E}, 0xE6D1}, /* P_GB_P4Q0 */
+ {MT9E013_16BIT, {0x3720}, 0xE0EC}, /* P_GB_P4Q1 */
+ {MT9E013_16BIT, {0x3722}, 0x6033}, /* P_GB_P4Q2 */
+ {MT9E013_16BIT, {0x3724}, 0x9DCE}, /* P_GB_P4Q3 */
+ {MT9E013_16BIT, {0x3726}, 0xA453}, /* P_GB_P4Q4 */
+ {MT9E013_16BIT, {0x3782}, 0x0614}, /* POLY_ORIGIN_C */
+ {MT9E013_16BIT, {0x3784}, 0x0494}, /* POLY_ORIGIN_R */
+ {MT9E013_16BIT, {0x37C0}, 0xC40A}, /* P_GR_Q5 */
+ {MT9E013_16BIT, {0x37C2}, 0xCE6A}, /* P_RD_Q5 */
+ {MT9E013_16BIT, {0x37C4}, 0xDBAA}, /* P_BL_Q5 */
+ {MT9E013_16BIT, {0x37C6}, 0xCCEA}, /* P_GB_Q5 */
+
+ /*STATE= Lens Correction Falloff, 70 */
+ {MT9E013_16BIT | MT9E013_RMW, {0x3780}, 0x8000, 1}, /* POLY_SC_ENABLE */
+ {MT9E013_TOK_TERM, {0}, 0}
+};
+
+#endif