summaryrefslogtreecommitdiff
path: root/drivers/media
diff options
context:
space:
mode:
authorRiham Haidar <rhaidar@nvidia.com>2013-05-30 10:36:16 -0700
committerRiham Haidar <rhaidar@nvidia.com>2013-05-30 10:36:16 -0700
commitd4dc214982830cb5afa6f281bc00f30612ba454a (patch)
tree86d2163e4638778dd15ee9bc3d5d5ad50d412321 /drivers/media
parentc6ee9bbf8a901359881d40a6ad9902aae44f4044 (diff)
parent59f86ac32f66bfc9d7378db82c18fac621e61765 (diff)
Merge remote-tracking branch 'origin/dev/svenkatarama/AOHDR_Merge' into promotion_build
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/video/tegra/Kconfig21
-rw-r--r--drivers/media/video/tegra/Makefile3
-rw-r--r--drivers/media/video/tegra/ar0833.c1266
-rw-r--r--drivers/media/video/tegra/ar0833_mode_tbls.c565
-rw-r--r--drivers/media/video/tegra/dw9718.c1077
-rw-r--r--drivers/media/video/tegra/imx132.c23
-rw-r--r--drivers/media/video/tegra/imx135.c2417
-rw-r--r--drivers/media/video/tegra/max77665-flash.c679
-rw-r--r--drivers/media/video/tegra/ov5693.c283
9 files changed, 5835 insertions, 499 deletions
diff --git a/drivers/media/video/tegra/Kconfig b/drivers/media/video/tegra/Kconfig
index ff576d67e6a5..6c88a0660197 100644
--- a/drivers/media/video/tegra/Kconfig
+++ b/drivers/media/video/tegra/Kconfig
@@ -68,6 +68,13 @@ config VIDEO_IMX091
This is a driver for the IMX091 camera sensor
for use with the tegra isp.
+config VIDEO_IMX135
+ tristate "IMX135 camera sensor support"
+ depends on I2C && ARCH_TEGRA
+ ---help---
+ This is a driver for the IMX135 camera sensor
+ for use with the tegra isp.
+
config VIDEO_IMX132
tristate "IMX132 camera sensor support"
depends on I2C && ARCH_TEGRA
@@ -154,3 +161,17 @@ config VIDEO_AD5816
---help---
This is a driver for the AD5816 focuser
for use with the tegra isp.
+
+config VIDEO_AR0833
+ tristate "AR0833 camera sensor support"
+ depends on I2C && ARCH_TEGRA
+ ---help---
+ This is a driver for the AR0833 camera sensor
+ for use with the tegra isp.
+
+config VIDEO_DW9718
+ tristate "DW9718 focuser support"
+ depends on I2C && ARCH_TEGRA
+ ---help---
+ This is a driver for the DW9718 focuser
+ for use with the tegra isp.
diff --git a/drivers/media/video/tegra/Makefile b/drivers/media/video/tegra/Makefile
index 7ce7bb077f77..b76e27b1a50c 100644
--- a/drivers/media/video/tegra/Makefile
+++ b/drivers/media/video/tegra/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_TEGRA_MEDIASERVER) += mediaserver/
obj-$(CONFIG_TEGRA_NVAVP) += nvavp/
obj-$(CONFIG_TEGRA_DTV) += tegra_dtv.o
obj-$(CONFIG_VIDEO_AR0832) += ar0832_main.o
+obj-$(CONFIG_VIDEO_AR0833) += ar0833.o
obj-$(CONFIG_VIDEO_OV5650) += ov5650.o
obj-$(CONFIG_VIDEO_OV5640) += ov5640.o
obj-$(CONFIG_VIDEO_OV14810) += ov14810.o
@@ -21,9 +22,11 @@ obj-$(CONFIG_TORCH_TPS61050) += tps61050.o
obj-$(CONFIG_MAX77665_FLASH) += max77665-flash.o
obj-$(CONFIG_TORCH_AS364X) += as364x.o
obj-$(CONFIG_VIDEO_SH532U) += sh532u.o
+obj-$(CONFIG_VIDEO_DW9718) += dw9718.o
obj-$(CONFIG_VIDEO_AD5820) += ad5820.o
obj-$(CONFIG_VIDEO_AD5816) += ad5816.o
obj-$(CONFIG_VIDEO_IMX091) += imx091.o
+obj-$(CONFIG_VIDEO_IMX135) += imx135.o
obj-$(CONFIG_VIDEO_IMX132) += imx132.o
obj-$(CONFIG_VIDEO_OV5693) += ov5693.o
obj-$(CONFIG_VIDEO_AD5823) += ad5823.o
diff --git a/drivers/media/video/tegra/ar0833.c b/drivers/media/video/tegra/ar0833.c
new file mode 100644
index 000000000000..701468fac6fd
--- /dev/null
+++ b/drivers/media/video/tegra/ar0833.c
@@ -0,0 +1,1266 @@
+/*
+ * ar0833.c - ar0833 sensor driver
+ *
+ * Copyright (c) 2013, NVIDIA CORPORATION, All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/i2c.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/gpio.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/atomic.h>
+#include <linux/regulator/consumer.h>
+#include <linux/export.h>
+#include <linux/module.h>
+
+#include <media/ar0833.h>
+
+#define SIZEOF_I2C_TRANSBUF 128
+
+struct ar0833_reg {
+ u16 addr;
+ u16 val;
+};
+
+struct ar0833_reg_blob {
+ u16 addr;
+ u16 size;
+ u8 *data;
+};
+
+struct ar0833_info {
+ struct miscdevice miscdev_info;
+ struct ar0833_power_rail power;
+ struct ar0833_sensordata sensor_data;
+ struct i2c_client *i2c_client;
+ struct ar0833_platform_data *pdata;
+ atomic_t in_use;
+ const struct ar0833_reg *mode;
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *debugfs_root;
+ u32 debug_i2c_offset;
+ int enableDCBLC;
+#endif
+ u8 i2c_trans_buf[SIZEOF_I2C_TRANSBUF];
+};
+
+#define AR0833_TABLE_WAIT_MS 0xC000
+#define AR0833_TABLE_NOP 0xC001
+#define AR0833_TABLE_CALL 0xC002
+#define AR0833_TABLE_BLOB 0xC003
+#define AR0833_TABLE_END 0xC004
+#define AR0833_TABLE_8BIT 0x8000
+
+#include "ar0833_mode_tbls.c"
+
+struct ar0833_mode_desc {
+ u16 xres;
+ u16 yres;
+ u8 hdr_en;
+ const struct ar0833_reg *mode_tbl;
+ struct ar0833_modeinfo mode_info;
+};
+
+static struct ar0833_mode_desc mode_table[] = {
+ {
+ .xres = 3264,
+ .yres = 2448,
+ .hdr_en = 0,
+ .mode_tbl = mode_3264x2448_30fps,
+ },
+ {
+ .xres = 3264,
+ .yres = 2448,
+ .hdr_en = 1,
+ .mode_tbl = mode_3264x2448_HDR_30fps,
+ },
+ {
+ .xres = 1920,
+ .yres = 1080,
+ .hdr_en = 0,
+ .mode_tbl = mode_1920x1080_30fps,
+ },
+ {
+ .xres = 1920,
+ .yres = 1080,
+ .hdr_en = 1,
+ .mode_tbl = mode_1920x1080_HDR_30fps,
+ },
+ {
+ .xres = 3264,
+ .yres = 1836,
+ .hdr_en = 0,
+ .mode_tbl = mode_3264x1836_30fps,
+ },
+ {
+ .xres = 3264,
+ .yres = 1836,
+ .hdr_en = 1,
+ .mode_tbl = mode_3264x1836_HDR_30fps,
+ },
+ { },
+};
+
+static long ar0833_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg);
+
+static inline void ar0833_msleep(u32 t)
+{
+ usleep_range(t*1000, t*1000 + 500);
+}
+
+static inline void ar0833_get_coarse_time_regs(struct ar0833_reg *regs,
+ u32 coarse_time)
+{
+ regs->addr = 0x0202;
+ regs->val = coarse_time & 0xFFFF;
+}
+
+static inline void ar0833_get_coarse_time_short_regs(struct ar0833_reg *regs,
+ u32 coarse_time)
+{
+ regs->addr = 0x3088;
+ regs->val = coarse_time & 0xFFFF;
+}
+
+static inline void ar0833_get_gain_reg(struct ar0833_reg *regs, u16 gain)
+{
+ regs->addr = 0x305E;
+ regs->val = gain & 0xFFFF;
+}
+
+static int ar0833_read_reg(struct i2c_client *client, u16 addr, u8 *val)
+{
+ int err;
+ struct i2c_msg msg[2];
+ unsigned char data[3];
+
+ if (!client->adapter)
+ return -ENODEV;
+
+ msg[0].addr = client->addr;
+ msg[0].flags = 0;
+ msg[0].len = 2;
+ msg[0].buf = data;
+
+ /* high byte goes out first */
+ data[0] = (u8) (addr >> 8);
+ data[1] = (u8) (addr & 0xff);
+
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = 1;
+ msg[1].buf = data + 2;
+
+ err = i2c_transfer(client->adapter, msg, 2);
+
+ if (err != 2)
+ return -EINVAL;
+
+ *val = data[2];
+
+ return 0;
+}
+
+static int ar0833_write_bulk_reg(struct i2c_client *client, u8 *data, int len)
+{
+ int err;
+ struct i2c_msg msg;
+
+ if (!client->adapter)
+ return -ENODEV;
+
+ msg.addr = client->addr;
+ msg.flags = 0;
+ msg.len = len;
+ msg.buf = data;
+
+ dev_dbg(&client->dev,
+ "%s {0x%04x,", __func__, (int)data[0] << 8 | data[1]);
+ for (err = 2; err < len; err++)
+ dev_dbg(&client->dev, " 0x%02x", data[err]);
+ dev_dbg(&client->dev, "},\n");
+
+ err = i2c_transfer(client->adapter, &msg, 1);
+ if (err == 1)
+ return 0;
+
+ dev_err(&client->dev, "ar0833: i2c bulk transfer failed at %x\n",
+ (int)data[0] << 8 | data[1]);
+
+ return err;
+}
+
+static int ar0833_write_reg8(struct i2c_client *client, u16 addr, u8 val)
+{
+ unsigned char data[3];
+
+ if (!client->adapter)
+ return -ENODEV;
+
+ data[0] = (u8) (addr >> 8);
+ data[1] = (u8) (addr & 0xff);
+ data[2] = (u8) (val & 0xff);
+
+ dev_dbg(&client->dev, "0x%x = 0x%x\n", addr, val);
+ return ar0833_write_bulk_reg(client, data, sizeof(data));
+}
+
+static int ar0833_write_reg16(struct i2c_client *client, u16 addr, u16 val)
+{
+ unsigned char data[4];
+
+ if (!client->adapter)
+ return -ENODEV;
+
+ data[0] = (u8) (addr >> 8);
+ data[1] = (u8) (addr & 0xff);
+ data[2] = (u8) (val >> 8);
+ data[3] = (u8) (val & 0xff);
+
+ dev_dbg(&client->dev, "0x%x = 0x%x\n", addr, val);
+ return ar0833_write_bulk_reg(client, data, sizeof(data));
+}
+
+/* flush and reset buffer */
+static int ar0833_flash_buffer(struct ar0833_info *info, int *len)
+{
+ int err;
+
+ if (!(*len))
+ return 0;
+
+ err = ar0833_write_bulk_reg(info->i2c_client,
+ info->i2c_trans_buf, *len);
+
+ *len = 0;
+ return err;
+}
+
+static int ar0833_write_blob(
+ struct ar0833_info *info, struct ar0833_reg_blob *pblob)
+{
+ u8 *pdata = pblob->data;
+ u16 addr = pblob->addr;
+ u16 size = pblob->size;
+ int err = 0;
+ u16 blk;
+
+ dev_dbg(&info->i2c_client->dev, "ar0833_write_blob ++\n");
+ while (size) {
+ blk = size > sizeof(info->i2c_trans_buf) - 2 ?
+ sizeof(info->i2c_trans_buf) - 2 : size;
+ info->i2c_trans_buf[0] = addr >> 8;
+ info->i2c_trans_buf[1] = (u8)addr;
+ memcpy(info->i2c_trans_buf + 2, pdata, blk);
+ err = ar0833_write_bulk_reg(info->i2c_client,
+ info->i2c_trans_buf, blk + 2);
+ if (err)
+ break;
+
+ size -= blk;
+ pdata += blk;
+ addr += blk;
+ }
+ dev_dbg(&info->i2c_client->dev, "ar0833_write_blob -- %d\n", err);
+ return err;
+}
+
+static int ar0833_write_table(
+ struct ar0833_info *info,
+ const struct ar0833_reg table[],
+ const struct ar0833_reg override_list[],
+ int num_override_regs)
+{
+ int err = 0;
+ const struct ar0833_reg *next, *n_next;
+ u8 *b_ptr = info->i2c_trans_buf;
+ unsigned int buf_filled = 0;
+ int i;
+ u16 val;
+
+ dev_dbg(&info->i2c_client->dev, "%s ++\n", __func__);
+ for (next = table; !err; next++) {
+ switch (next->addr) {
+ case AR0833_TABLE_END:
+ dev_dbg(&info->i2c_client->dev, "ar0833_table_end\n");
+ err = ar0833_flash_buffer(info, &buf_filled);
+ return err;
+ case AR0833_TABLE_NOP:
+ continue;
+ case AR0833_TABLE_WAIT_MS:
+ dev_dbg(&info->i2c_client->dev,
+ "ar0833_wait_ms %d\n", next->val);
+ err = ar0833_flash_buffer(info, &buf_filled);
+ if (err < 0)
+ return err;
+ ar0833_msleep(next->val);
+ continue;
+ case AR0833_TABLE_CALL:
+ err = ar0833_flash_buffer(info, &buf_filled);
+ if (next->val >= NUM_OF_SUBTBLS) {
+ dev_err(&info->i2c_client->dev,
+ "%s: invalid tbl index %d\n",
+ __func__, next->val);
+ return -EFAULT;
+ }
+ if (err < 0)
+ return err;
+
+ err = ar0833_write_table(
+ info, sub_tbls[next->val], NULL, 0);
+ if (err < 0)
+ return err;
+ continue;
+ case AR0833_TABLE_BLOB:
+ err = ar0833_flash_buffer(info, &buf_filled);
+ if (next->val >= NUM_OF_SUBTBLS) {
+ dev_err(&info->i2c_client->dev,
+ "%s: invalid tbl index %d\n",
+ __func__, next->val);
+ return -EFAULT;
+ }
+ if (err < 0)
+ return err;
+
+ err = ar0833_write_blob(info, sub_tbls[next->val]);
+ if (err < 0)
+ return err;
+ continue;
+ }
+
+ val = next->val;
+ /* When an override list is passed in, replace the reg */
+ /* value to write if the reg is in the list */
+ if (override_list)
+ for (i = 0; i < num_override_regs; i++)
+ if (next->addr == override_list[i].addr) {
+ val = override_list[i].val;
+ break;
+ }
+
+ if (!buf_filled) {
+ b_ptr = info->i2c_trans_buf;
+ *b_ptr++ = (next->addr & ~AR0833_TABLE_8BIT) >> 8;
+ *b_ptr++ = next->addr & 0xff;
+ buf_filled = 2;
+ }
+ if (!(next->addr & AR0833_TABLE_8BIT)) {
+ *b_ptr++ = (u8)(val >> 8);
+ buf_filled++;
+ }
+ *b_ptr++ = (u8)val;
+ buf_filled++;
+
+ n_next = next + 1;
+ if (buf_filled < (sizeof(info->i2c_trans_buf) & 0xFFFE) &&
+ n_next->addr == next->addr + 2)
+ continue;
+ err = ar0833_flash_buffer(info, &buf_filled);
+ if (err < 0)
+ return err;
+ }
+ dev_dbg(&info->i2c_client->dev, "%s --\n", __func__);
+ return 0;
+}
+
+static int ar0833_set_coarse_time(struct ar0833_info *info, u32 coarse_time,
+ bool group_hold)
+{
+ int ret;
+ struct ar0833_reg reg_list;
+
+ ar0833_get_coarse_time_regs(&reg_list, coarse_time);
+
+ if (group_hold) {
+ ret = ar0833_write_reg16(info->i2c_client, 0x0104, 0x1);
+ if (ret)
+ return ret;
+ }
+
+ ret = ar0833_write_reg16(info->i2c_client, reg_list.addr,
+ reg_list.val);
+ if (ret)
+ return ret;
+
+ if (group_hold) {
+ ret = ar0833_write_reg16(info->i2c_client, 0x0104, 0x0);
+ if (ret)
+ return ret;
+ }
+ return ret;
+}
+
+static int ar0833_set_hdr_coarse_time(struct ar0833_info *info,
+ struct ar0833_hdr *values,
+ bool group_hold)
+{
+ int ret;
+ struct ar0833_reg reg_list;
+ struct ar0833_reg reg_list_short;
+
+ ar0833_get_coarse_time_regs(&reg_list, values->coarse_time_long);
+ ar0833_get_coarse_time_short_regs(&reg_list_short,
+ values->coarse_time_short);
+
+ if (group_hold) {
+ ret = ar0833_write_reg16(info->i2c_client, 0x0104, 0x1);
+ if (ret)
+ return ret;
+ }
+
+ ret = ar0833_write_reg16(info->i2c_client, reg_list.addr,
+ reg_list.val);
+ if (ret)
+ return ret;
+
+ ret = ar0833_write_reg16(info->i2c_client, reg_list_short.addr,
+ reg_list_short.val);
+ if (ret)
+ return ret;
+
+ if (group_hold) {
+ ret = ar0833_write_reg16(info->i2c_client, 0x0104, 0x0);
+ if (ret)
+ return ret;
+ }
+ return ret;
+}
+
+static int ar0833_set_gain(struct ar0833_info *info, u16 gain,
+ bool group_hold)
+{
+ int ret;
+ struct ar0833_reg reg_list;
+
+ ar0833_get_gain_reg(&reg_list, gain);
+
+ if (group_hold) {
+ ret = ar0833_write_reg16(info->i2c_client, 0x0104, 0x1);
+ if (ret)
+ return ret;
+ }
+
+ ret = ar0833_write_reg16(info->i2c_client, reg_list.addr,
+ reg_list.val);
+ if (ret)
+ return ret;
+
+ if (group_hold) {
+ ret = ar0833_write_reg16(info->i2c_client, 0x0104, 0x0);
+ if (ret)
+ return ret;
+ }
+ return ret;
+}
+
+static int
+ar0833_set_group_hold(struct ar0833_info *info, struct ar0833_ae *ae)
+{
+ int ret;
+ int count = 0;
+ bool groupHoldEnabled = false;
+ struct ar0833_hdr values;
+
+ values.coarse_time_long = ae->coarse_time;
+ values.coarse_time_short = ae->coarse_time_short;
+
+ if (ae->gain_enable)
+ count++;
+ if (ae->coarse_time_enable)
+ count++;
+ if (count >= 1)
+ groupHoldEnabled = true;
+
+ if (groupHoldEnabled) {
+ ret = ar0833_write_reg16(info->i2c_client, 0x104, 0x1);
+ if (ret)
+ return ret;
+ }
+
+ if (ae->gain_enable)
+ ar0833_set_gain(info, ae->gain, false);
+ if (ae->coarse_time_enable)
+ ar0833_set_hdr_coarse_time(info, &values, false);
+
+ if (groupHoldEnabled) {
+ ret = ar0833_write_reg16(info->i2c_client, 0x104, 0x0);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ar0833_get_status(struct ar0833_info *info, u8 *status)
+{
+ int err;
+
+ err = ar0833_read_reg(info->i2c_client, 0x380e, status);
+ return err;
+}
+
+static int ar0833_open(struct inode *inode, struct file *file)
+{
+ struct miscdevice *miscdev = file->private_data;
+ struct ar0833_info *info;
+
+ info = container_of(miscdev, struct ar0833_info, miscdev_info);
+ /* check if the device is in use */
+ if (atomic_xchg(&info->in_use, 1)) {
+ dev_info(&info->i2c_client->dev, "%s:BUSY!\n", __func__);
+ return -EBUSY;
+ }
+
+ file->private_data = info;
+
+ if (info->pdata && info->pdata->power_on)
+ info->pdata->power_on(&info->power);
+ else {
+ dev_err(&info->i2c_client->dev,
+ "%s:no valid power_on function.\n", __func__);
+ return -EEXIST;
+ }
+ return 0;
+}
+
+int ar0833_release(struct inode *inode, struct file *file)
+{
+ struct ar0833_info *info = file->private_data;
+
+ if (info->pdata && info->pdata->power_off)
+ info->pdata->power_off(&info->power);
+ file->private_data = NULL;
+
+ /* warn if device is already released */
+ WARN_ON(!atomic_xchg(&info->in_use, 0));
+ return 0;
+}
+
+static int ar0833_regulator_get(struct ar0833_info *info,
+ struct regulator **vreg, char vreg_name[])
+{
+ struct regulator *reg = NULL;
+ int err = 0;
+
+ reg = regulator_get(&info->i2c_client->dev, vreg_name);
+ if (unlikely(IS_ERR(reg))) {
+ dev_err(&info->i2c_client->dev, "%s %s ERR: %d\n",
+ __func__, vreg_name, (int)reg);
+ err = PTR_ERR(reg);
+ reg = NULL;
+ } else
+ dev_dbg(&info->i2c_client->dev, "%s: %s\n",
+ __func__, vreg_name);
+
+ *vreg = reg;
+ return err;
+}
+
+static int ar0833_power_get(struct ar0833_info *info)
+{
+ struct ar0833_power_rail *pw = &info->power;
+
+ ar0833_regulator_get(info, &pw->avdd, "vana"); /* ananlog 2.7v */
+ ar0833_regulator_get(info, &pw->dvdd, "vdig"); /* digital 1.2v */
+ ar0833_regulator_get(info, &pw->iovdd, "vif"); /* interface 1.8v */
+
+ return 0;
+}
+
+static const struct file_operations ar0833_fileops = {
+ .owner = THIS_MODULE,
+ .open = ar0833_open,
+ .unlocked_ioctl = ar0833_ioctl,
+ .release = ar0833_release,
+};
+
+static struct miscdevice ar0833_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "ar0833",
+ .fops = &ar0833_fileops,
+};
+
+#ifdef CONFIG_DEBUG_FS
+int control_DC_BLC(struct ar0833_info *info)
+{
+ u8 reg0x3d0a;
+ u8 reg0x3d0b;
+ u8 reg0x4006;
+
+ if (info->enableDCBLC) {
+ ar0833_write_reg8(info->i2c_client, 0x3d84, 0xdf);
+ ar0833_write_reg8(info->i2c_client, 0x3d81, 0x01);
+ ar0833_msleep(10);
+
+ ar0833_read_reg(info->i2c_client, 0x3d0a, &reg0x3d0a);
+ ar0833_read_reg(info->i2c_client, 0x3d0b, &reg0x3d0b);
+ ar0833_write_reg8(info->i2c_client, 0x3d81, 0x00);
+
+ if ((reg0x3d0b > 0x10 && reg0x3d0b < 0x20))
+ reg0x4006 = reg0x3d0b;
+ else if ((reg0x3d0a > 0x10) && (reg0x3d0a < 0x20))
+ reg0x4006 = reg0x3d0a;
+ else
+ reg0x4006 = 0x20;
+
+ ar0833_write_reg8(info->i2c_client, 0x4006, reg0x4006);
+ dev_info(&info->i2c_client->dev,
+ "ar0833: %s: wrote the DC BLC commands\n",
+ __func__);
+ } else {
+ dev_info(&info->i2c_client->dev,
+ "ar0833: %s: DID NOT do the DC BLC commands\n",
+ __func__);
+ }
+
+ return 0;
+}
+
+static int ar0833_stats_show(struct seq_file *s, void *data)
+{
+ static struct ar0833_info *info;
+
+ seq_printf(s, "%-20s : %-20s\n", "Name", "ar0833-debugfs-testing");
+ seq_printf(s, "%-20s : 0x%X\n", "Current i2c-offset Addr",
+ info->debug_i2c_offset);
+ seq_printf(s, "%-20s : 0x%X\n", "DC BLC Enabled",
+ info->debug_i2c_offset);
+ return 0;
+}
+
+static int ar0833_stats_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ar0833_stats_show, inode->i_private);
+}
+
+static const struct file_operations ar0833_stats_fops = {
+ .open = ar0833_stats_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int debug_i2c_offset_w(void *data, u64 val)
+{
+ struct ar0833_info *info = (struct ar0833_info *)(data);
+ dev_info(&info->i2c_client->dev,
+ "ar0833:%s setting i2c offset to 0x%X\n",
+ __func__, (u32)val);
+ info->debug_i2c_offset = (u32)val;
+ dev_info(&info->i2c_client->dev,
+ "ar0833:%s new i2c offset is 0x%X\n", __func__,
+ info->debug_i2c_offset);
+ return 0;
+}
+
+static int debug_i2c_offset_r(void *data, u64 *val)
+{
+ struct ar0833_info *info = (struct ar0833_info *)(data);
+ *val = (u64)info->debug_i2c_offset;
+ dev_info(&info->i2c_client->dev,
+ "ar0833:%s reading i2c offset is 0x%X\n", __func__,
+ info->debug_i2c_offset);
+ return 0;
+}
+
+static int debug_i2c_read(void *data, u64 *val)
+{
+ struct ar0833_info *info = (struct ar0833_info *)(data);
+ u8 temp1 = 0;
+ u8 temp2 = 0;
+ dev_info(&info->i2c_client->dev,
+ "ar0833:%s reading offset 0x%X\n", __func__,
+ info->debug_i2c_offset);
+ if (ar0833_read_reg(info->i2c_client,
+ info->debug_i2c_offset, &temp1)
+ || ar0833_read_reg(info->i2c_client,
+ info->debug_i2c_offset+1, &temp2)) {
+ dev_err(&info->i2c_client->dev,
+ "ar0833:%s failed\n", __func__);
+ return -EIO;
+ }
+ dev_info(&info->i2c_client->dev,
+ "ar0833:%s read value is 0x%X\n", __func__,
+ temp1<<8 | temp2);
+ *val = (u64)(temp1<<8 | temp2);
+ return 0;
+}
+
+static int debug_i2c_write(void *data, u64 val)
+{
+ struct ar0833_info *info = (struct ar0833_info *)(data);
+ dev_info(&info->i2c_client->dev,
+ "ar0833:%s writing 0x%X to offset 0x%X\n", __func__,
+ (u16)val, info->debug_i2c_offset);
+ if (ar0833_write_reg16(info->i2c_client,
+ info->debug_i2c_offset, (u16)val)) {
+ dev_err(&info->i2c_client->dev, "ar0833:%s failed\n", __func__);
+ return -EIO;
+ }
+ return 0;
+}
+
+static int debug_dcblc_r(void *data, u64 *val)
+{
+ struct ar0833_info *info = (struct ar0833_info *)(data);
+ *val = (u64)info->enableDCBLC;
+ dev_info(&info->i2c_client->dev,
+ "ar0833:%s read DC BLC [%d]\n", __func__,
+ info->enableDCBLC);
+
+ return 0;
+}
+
+static int debug_dcblc_w(void *data, u64 val)
+{
+ struct ar0833_info *info = (struct ar0833_info *)(data);
+ if (val != 0) {
+ info->enableDCBLC = 1;
+ dev_info(&info->i2c_client->dev,
+ "ar0833:%s enabled DC BLC\n", __func__);
+ } else {
+ info->enableDCBLC = 0;
+ dev_info(&info->i2c_client->dev,
+ "ar0833:%s disabled DC BLC\n", __func__);
+ }
+
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(debug_dcblc_fops, debug_dcblc_r,
+ debug_dcblc_w, "0x%llx\n");
+DEFINE_SIMPLE_ATTRIBUTE(i2c_offset_fops, debug_i2c_offset_r,
+ debug_i2c_offset_w, "0x%llx\n");
+DEFINE_SIMPLE_ATTRIBUTE(i2c_read_fops, debug_i2c_read,
+ /*debug_i2c_dummy_w*/ NULL, "0x%llx\n");
+DEFINE_SIMPLE_ATTRIBUTE(i2c_write_fops, /*debug_i2c_dummy_r*/NULL,
+ debug_i2c_write, "0x%llx\n");
+
+static int ar0833_debug_init(struct ar0833_info *info)
+{
+ dev_dbg(&info->i2c_client->dev, "%s", __func__);
+
+ info->debugfs_root = debugfs_create_dir(ar0833_device.name, NULL);
+
+ if (!info->debugfs_root)
+ goto err_out;
+
+ if (!debugfs_create_file("stats", S_IRUGO,
+ info->debugfs_root, info, &ar0833_stats_fops))
+ goto err_out;
+
+ if (!debugfs_create_file("i2c_offset", S_IRUGO | S_IWUSR,
+ info->debugfs_root, info, &i2c_offset_fops))
+ goto err_out;
+
+ if (!debugfs_create_file("i2c_read", S_IRUGO,
+ info->debugfs_root, info, &i2c_read_fops))
+ goto err_out;
+
+ if (!debugfs_create_file("i2c_write", S_IWUSR,
+ info->debugfs_root, info, &i2c_write_fops))
+ goto err_out;
+
+ if (!debugfs_create_file("DCBLC", S_IRUGO | S_IWUSR,
+ info->debugfs_root, info, &debug_dcblc_fops))
+ goto err_out;
+
+ return 0;
+
+err_out:
+ dev_err(&info->i2c_client->dev, "ERROR:%s failed", __func__);
+ if (info->debugfs_root)
+ debugfs_remove_recursive(info->debugfs_root);
+ return -ENOMEM;
+}
+#endif
+
+static struct ar0833_modeinfo def_modeinfo = {
+ .xres = 3264,
+ .yres = 2448,
+ .hdr = 0,
+ .lanes = 4,
+ .line_len = 0x0f68,
+ .frame_len = 0x0a01,
+ .coarse_time = 2400,
+ .coarse_time_2nd = 300,
+ .xstart = 8,
+ .xend = 0x0cc7,
+ .ystart = 8,
+ .yend = 0x0997,
+ .xsize = 0x0cc0,
+ .ysize = 0x0990,
+ .gain = 0x1000,
+ .x_flip = 1,
+ .y_flip = 0,
+ .x_bin = 1,
+ .y_bin = 1,
+ .vt_pix_clk_div = 5,
+ .vt_sys_clk_div = 1,
+ .pre_pll_clk_div = 2,
+ .pll_multi = 0x40,
+ .op_pix_clk_div = 0x0a,
+ .op_sys_clk_div = 1,
+};
+
+static struct ar0833_mode_desc *ar0833_get_mode(
+ struct ar0833_info *info, struct ar0833_mode *mode)
+{
+ struct ar0833_mode_desc *mt = mode_table;
+
+ while (mt->xres) {
+ if ((mt->xres == mode->xres) &&
+ (mt->yres == mode->yres) &&
+ (mt->hdr_en == mode->hdr_en))
+ break;
+ mt++;
+ }
+
+ if (!mt->xres)
+ mt = NULL;
+ return mt;
+}
+
+static int ar0833_mode_info_init(struct ar0833_info *info)
+{
+ struct ar0833_mode_desc *md = mode_table;
+ const struct ar0833_reg *mt;
+ struct ar0833_modeinfo *mi;
+
+ dev_dbg(&info->i2c_client->dev, "%s", __func__);
+ while (md->xres) {
+ mi = &md->mode_info;
+ mt = md->mode_tbl;
+ memcpy(mi, &def_modeinfo, sizeof(*mi));
+ dev_dbg(&info->i2c_client->dev, "mode %d x %d %s",
+ md->xres, md->yres, md->hdr_en ? "HDR" : "REG");
+ mi->xres = md->xres;
+ mi->yres = md->yres;
+ mi->hdr = md->hdr_en;
+ while (mt->addr != AR0833_TABLE_END) {
+ switch (mt->addr) {
+ case 0x0300:
+ mi->vt_pix_clk_div = mt->val;
+ break;
+ case 0x0302:
+ mi->vt_sys_clk_div = mt->val;
+ break;
+ case 0x0304:
+ mi->pre_pll_clk_div = mt->val;
+ break;
+ case 0x0306:
+ mi->pll_multi = mt->val;
+ break;
+ case 0x0308:
+ mi->op_pix_clk_div = mt->val;
+ break;
+ case 0x030a:
+ mi->op_sys_clk_div = mt->val;
+ break;
+ case 0x0202:
+ mi->coarse_time = mt->val;
+ break;
+ case 0x3088:
+ mi->coarse_time_2nd = mt->val;
+ break;
+ case 0x0340:
+ mi->frame_len = mt->val;
+ break;
+ case 0x0342:
+ mi->line_len = mt->val;
+ break;
+ case 0x0344:
+ mi->xstart = mt->val;
+ break;
+ case 0x0346:
+ mi->ystart = mt->val;
+ break;
+ case 0x0348:
+ mi->xend = mt->val;
+ break;
+ case 0x034a:
+ mi->yend = mt->val;
+ break;
+ case 0x034c:
+ mi->xsize = mt->val;
+ break;
+ case 0x034e:
+ mi->ysize = mt->val;
+ break;
+ case 0x305e:
+ mi->gain = mt->val;
+ break;
+ case 0x31ae:
+ mi->lanes = mt->val & 0x7;
+ break;
+ case 0x3040:
+ if (mt->val & 0x8000)
+ mi->y_flip = 1;
+ if (mt->val & 0x4000)
+ mi->x_flip = 1;
+ switch (mt->val & 0x1c0) {
+ case 1:
+ mi->x_bin = 1;
+ break;
+ case 3:
+ mi->x_bin = 2;
+ break;
+ case 7:
+ mi->x_bin = 4;
+ break;
+ default:
+ dev_warn(&info->i2c_client->dev,
+ "%s :Unrecognized x_odd_inc"
+ "setting in mode %d x %d %s,"
+ " 0x3040 = 0x%x\n",
+ __func__, md->xres, md->yres,
+ md->hdr_en ? "HDR" : "REG",
+ mt->val);
+ break;
+ }
+
+ switch (mt->val & 0x3f) {
+ case 1:
+ mi->y_bin = 1;
+ break;
+ case 3:
+ mi->y_bin = 2;
+ break;
+ case 7:
+ mi->y_bin = 4;
+ break;
+ case 15:
+ mi->y_bin = 8;
+ break;
+ case 31:
+ mi->y_bin = 16;
+ break;
+ case 63:
+ mi->y_bin = 32;
+ break;
+ default:
+ dev_warn(&info->i2c_client->dev,
+ "%s :Unrecognized y_odd_inc"
+ "setting in mode %d x %d %s,"
+ " 0x3040 = 0x%x\n",
+ __func__, md->xres, md->yres,
+ md->hdr_en ? "HDR" : "REG",
+ mt->val);
+ break;
+ }
+ break;
+ };
+ mt++;
+ };
+ md++;
+ }
+ return 0;
+}
+
+static struct ar0833_modeinfo *ar0833_get_mode_info(
+ struct ar0833_info *info, struct ar0833_modeinfo *mi)
+{
+ struct ar0833_mode mode;
+ struct ar0833_mode_desc *mode_desc;
+
+ mode.xres = mi->xres;
+ mode.yres = mi->yres;
+ mode.hdr_en = mi->hdr;
+ mode_desc = ar0833_get_mode(info, &mode);
+ if (mode_desc == NULL) {
+ dev_err(&info->i2c_client->dev,
+ "%s: invalid params to get mode info %d %d %d\n",
+ __func__, mi->xres, mi->yres, mi->hdr);
+ return NULL;
+ }
+
+ return &mode_desc->mode_info;
+}
+
+static int ar0833_set_mode(struct ar0833_info *info, struct ar0833_mode *mode)
+{
+ struct ar0833_mode_desc *sensor_mode;
+ struct ar0833_reg reg_list[4];
+ int err;
+
+ dev_info(&info->i2c_client->dev,
+ "%s: xres %u yres %u hdr %d\n",
+ __func__, mode->xres, mode->yres, mode->hdr_en);
+ dev_info(&info->i2c_client->dev,
+ "framelength %u coarsetime %u gain %x\n",
+ mode->frame_length, mode->coarse_time, mode->gain);
+
+ sensor_mode = ar0833_get_mode(info, mode);
+ if (sensor_mode == NULL) {
+ dev_err(&info->i2c_client->dev,
+ "%s: invalid params supplied to set mode %d %d %d\n",
+ __func__, mode->xres, mode->yres, mode->hdr_en);
+ return -EINVAL;
+ }
+
+ if (mode->hdr_en == 1) /* if HDR is enabled */
+ dev_info(&info->i2c_client->dev, "ar0833 HDR enabled\n");
+ else
+ dev_info(&info->i2c_client->dev, "ar0833 HDR disabled\n");
+
+ memset(reg_list, 0, sizeof(reg_list));
+ /* get a list of override regs for the asking frame length, */
+ /* coarse integration time, and gain. */
+ ar0833_get_coarse_time_regs(reg_list, mode->coarse_time);
+ ar0833_get_gain_reg(reg_list + 1, mode->gain);
+ if (mode->hdr_en == 1) /* if HDR is enabled */
+ ar0833_get_coarse_time_short_regs(
+ reg_list + 2, mode->coarse_time_short);
+
+ err = ar0833_write_table(
+ info, sensor_mode->mode_tbl, reg_list, mode->hdr_en ? 3 : 2);
+ if (err)
+ return err;
+
+ info->mode = sensor_mode->mode_tbl;
+
+#ifdef CONFIG_DEBUG_FS
+ control_DC_BLC(info);
+#endif
+
+ return 0;
+}
+
+static long ar0833_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int err = 0;
+ struct ar0833_info *info = file->private_data;
+
+ switch (cmd) {
+ case AR0833_IOCTL_SET_MODE:
+ {
+ struct ar0833_mode mode;
+
+ dev_dbg(&info->i2c_client->dev, "AR0833_IOCTL_SET_MODE\n");
+ if (copy_from_user(&mode, (const void __user *)arg,
+ sizeof(struct ar0833_mode))) {
+ err = -EFAULT;
+ break;
+ }
+ err = ar0833_set_mode(info, &mode);
+ break;
+ }
+ case AR0833_IOCTL_SET_FRAME_LENGTH:
+ dev_dbg(&info->i2c_client->dev,
+ "AR0833_IOCTL_SET_FRAME_LENGTH %x\n", (u32)arg);
+ /* obsolete. we should not update frame length,
+ it is done by sensor automatically */
+ break;
+ case AR0833_IOCTL_SET_COARSE_TIME:
+ dev_dbg(&info->i2c_client->dev,
+ "AR0833_IOCTL_SET_COARSE_TIME %x\n", (u32)arg);
+ err = ar0833_set_coarse_time(info, (u32)arg, true);
+ break;
+ case AR0833_IOCTL_SET_HDR_COARSE_TIME:
+ {
+ struct ar0833_hdr values;
+
+ dev_dbg(&info->i2c_client->dev,
+ "AR0833_IOCTL_SET_HDR_COARSE_TIME\n");
+ if (copy_from_user(&values,
+ (const void __user *)arg,
+ sizeof(struct ar0833_hdr))) {
+ err = -EFAULT;
+ break;
+ }
+ err = ar0833_set_hdr_coarse_time(info, &values, true);
+ break;
+ }
+ case AR0833_IOCTL_SET_GAIN:
+ dev_dbg(&info->i2c_client->dev,
+ "AR0833_IOCTL_SET_GAIN %x\n", (u32)arg);
+ err = ar0833_set_gain(info, (u16)arg, true);
+ break;
+ case AR0833_IOCTL_SET_GROUP_HOLD:
+ {
+ struct ar0833_ae ae;
+ if (copy_from_user(&ae, (const void __user *)arg,
+ sizeof(struct ar0833_ae))) {
+ dev_err(&info->i2c_client->dev,
+ "%s:fail group hold\n", __func__);
+ return -EFAULT;
+ }
+ return ar0833_set_group_hold(info, &ae);
+ }
+ case AR0833_IOCTL_GET_STATUS:
+ {
+ u8 status;
+
+ dev_dbg(&info->i2c_client->dev, "AR0833_IOCTL_GET_STATUS\n");
+ err = ar0833_get_status(info, &status);
+ if (err)
+ break;
+ if (copy_to_user((void __user *)arg, &status, 2)) {
+ err = -EFAULT;
+ break;
+ }
+ break;
+ }
+ case AR0833_IOCTL_GET_MODE:
+ {
+ struct ar0833_modeinfo mode_info, *mi;
+
+ dev_dbg(&info->i2c_client->dev, "AR0833_IOCTL_GET_MODE\n");
+ if (copy_from_user(&mode_info,
+ (const void __user *)arg,
+ sizeof(struct ar0833_mode))) {
+ err = -EFAULT;
+ break;
+ }
+ mi = ar0833_get_mode_info(info, &mode_info);
+ if (mi == NULL)
+ err = -EFAULT;
+ else {
+ if (copy_to_user((void __user *)arg, mi, sizeof(*mi))) {
+ err = -EFAULT;
+ break;
+ }
+ dev_dbg(&info->i2c_client->dev, "mode %d x %d %s:\n",
+ mi->xres, mi->yres, mi->hdr ? "HDR" : "REG");
+ dev_dbg(&info->i2c_client->dev,
+ "line_len = %d\n", mi->line_len);
+ dev_dbg(&info->i2c_client->dev,
+ "frame_len = %d\n", mi->frame_len);
+ dev_dbg(&info->i2c_client->dev,
+ "xsize = %d\n", mi->xsize);
+ dev_dbg(&info->i2c_client->dev,
+ "ysize = %d\n", mi->ysize);
+ dev_dbg(&info->i2c_client->dev,
+ "vt_pix_clk_div = %d\n", mi->vt_pix_clk_div);
+ dev_dbg(&info->i2c_client->dev,
+ "vt_sys_clk_div = %d\n", mi->vt_sys_clk_div);
+ dev_dbg(&info->i2c_client->dev,
+ "pre_pll_clk_div = %d\n", mi->pre_pll_clk_div);
+ dev_dbg(&info->i2c_client->dev,
+ "pll_multi = %d\n", mi->pll_multi);
+ dev_dbg(&info->i2c_client->dev,
+ "op_pix_clk_div = %d\n", mi->op_pix_clk_div);
+ dev_dbg(&info->i2c_client->dev,
+ "op_sys_clk_div = %d\n", mi->op_sys_clk_div);
+ }
+ break;
+ }
+ default:
+ dev_dbg(&info->i2c_client->dev, "INVALID IOCTL\n");
+ err = -EINVAL;
+ }
+
+ if (err)
+ dev_dbg(&info->i2c_client->dev,
+ "%s - %x: ERR = %d\n", __func__, cmd, err);
+ return err;
+}
+
+static int ar0833_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int err;
+ struct ar0833_info *info;
+ dev_info(&client->dev, "ar0833: probing sensor.\n");
+
+ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL);
+ if (info == NULL) {
+ dev_err(&client->dev, "%s: kzalloc error\n", __func__);
+ return -ENOMEM;
+ }
+
+ info->pdata = client->dev.platform_data;
+ info->i2c_client = client;
+ atomic_set(&info->in_use, 0);
+ info->mode = NULL;
+
+ i2c_set_clientdata(client, info);
+
+ ar0833_power_get(info);
+ ar0833_mode_info_init(info);
+
+ memcpy(&info->miscdev_info,
+ &ar0833_device,
+ sizeof(struct miscdevice));
+
+ err = misc_register(&info->miscdev_info);
+ if (err) {
+ dev_err(&info->i2c_client->dev,
+ "ar0833: Unable to register misc device!\n");
+ kfree(info);
+ return err;
+ }
+#ifdef CONFIG_DEBUG_FS
+ ar0833_debug_init(info);
+ info->enableDCBLC = 0;
+#endif
+
+ return 0;
+}
+
+static int ar0833_remove(struct i2c_client *client)
+{
+ struct ar0833_info *info;
+ info = i2c_get_clientdata(client);
+ misc_deregister(&info->miscdev_info);
+ kfree(info);
+
+#ifdef CONFIG_DEBUG_FS
+ if (info->debugfs_root)
+ debugfs_remove_recursive(info->debugfs_root);
+#endif
+
+ return 0;
+}
+
+static const struct i2c_device_id ar0833_id[] = {
+ { "ar0833", 0 },
+ { },
+};
+
+MODULE_DEVICE_TABLE(i2c, ar0833_id);
+
+static struct i2c_driver ar0833_i2c_driver = {
+ .driver = {
+ .name = "ar0833",
+ .owner = THIS_MODULE,
+ },
+ .probe = ar0833_probe,
+ .remove = ar0833_remove,
+ .id_table = ar0833_id,
+};
+
+static int __init ar0833_init(void)
+{
+ pr_info("ar0833 sensor driver loading\n");
+ return i2c_add_driver(&ar0833_i2c_driver);
+}
+
+static void __exit ar0833_exit(void)
+{
+ i2c_del_driver(&ar0833_i2c_driver);
+}
+
+module_init(ar0833_init);
+module_exit(ar0833_exit);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/tegra/ar0833_mode_tbls.c b/drivers/media/video/tegra/ar0833_mode_tbls.c
new file mode 100644
index 000000000000..39a3db3bb717
--- /dev/null
+++ b/drivers/media/video/tegra/ar0833_mode_tbls.c
@@ -0,0 +1,565 @@
+/*
+ * ar0833_mode_tbls.c - ar0833 sensor mode table
+ *
+ * Copyright (c) 2013, NVIDIA CORPORATION, All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ */
+
+static struct ar0833_reg Reset_tbl[] = {
+ {0x301A, 0x0019},
+ {AR0833_TABLE_WAIT_MS, 1},
+ /* Disable Streaming */
+ {0x301A, 0x0218},
+ {AR0833_TABLE_END, 0x0000},
+};
+
+/*All image captures should be taken with these settings */
+static struct ar0833_reg Default_3P_tbl[] = {
+ {0x3042, 0x0000},
+ {0x30C0, 0x1810},
+ {0x30C8, 0x0018},
+ {0x30D2, 0x0000},
+ {0x30D4, 0xD030},
+ {0x30D6, 0x2200},
+ {0x30DA, 0x0080},
+ {0x30DC, 0x0080},
+ {0x30EE, 0x0340},
+ {0x316A, 0x8800},
+ {0x316C, 0x8200},
+ {0x3172, 0x0286},
+ {0x3174, 0x8000},
+ {0x317C, 0xE103},
+ {0x3180, 0xF0FF},
+ {0x31E0, 0x0741},
+ {0x3ECC, 0x0056},
+ {0x3ED0, 0xA8AA},
+ {0x3ED2, 0xAAA8},
+ {0x3ED4, 0x8ACC},
+ {0x3ED8, 0x7288},
+ {0x3EDA, 0x77CA},
+ {0x3EDE, 0x6664},
+ {0x3EE0, 0x26D5},
+ {0x3EE4, 0x1548},
+ {0x3EE6, 0xB10C},
+ {0x3EE8, 0x6E79},
+ {0x3EFE, 0x77CC},
+ {0x31E6, 0x0000},
+ {0x3F00, 0x0028},
+ {0x3F02, 0x0140},
+ {0x3F04, 0x0002},
+ {0x3F06, 0x0004},
+ {0x3F08, 0x0008},
+ {0x3F0A, 0x0B09},
+ {0x3F0C, 0x0302},
+ {0x3F10, 0x0505},
+ {0x3F12, 0x0303},
+ {0x3F14, 0x0101},
+ {0x3F16, 0x2020},
+ {0x3F18, 0x0404},
+ {0x3F1A, 0x7070},
+ {0x3F1C, 0x003A},
+ {0x3F1E, 0x003C},
+ {0x3F2C, 0x2210},
+ {0x3F40, 0x2020},
+ {0x3F42, 0x0808},
+ {0x3F44, 0x0101},
+ {AR0833_TABLE_END, 0x0000},
+};
+
+u8 Sequencer_Adjustment_v7p2_data[] = {
+ 0x04, 0x70, 0xC8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x6F, 0x40, 0x14,
+ 0x0E, 0x23, 0x82, 0x41, 0x5C, 0x54, 0x6E, 0x42, 0x00, 0xC0, 0x5D,
+ 0x80, 0x5A, 0x80, 0x57, 0x84, 0x64, 0x80, 0x55, 0x86, 0x64, 0x80,
+ 0x65, 0x88, 0x65, 0x84, 0x58, 0x80, 0x00, 0xC0, 0x80, 0x30, 0x0C,
+ 0x84, 0x42, 0x82, 0x10, 0x30, 0xA6, 0x5B, 0x80, 0x63, 0x8B, 0x30,
+ 0x0C, 0xA5, 0x59, 0x84, 0x6C, 0x80, 0x6D, 0x81, 0x5F, 0x60, 0x61,
+ 0x10, 0x30, 0x88, 0x66, 0x83, 0x6E, 0x80, 0x64, 0x87, 0x64, 0x30,
+ 0x50, 0xDA, 0x6A, 0x83, 0x6B, 0xA6, 0x30, 0x94, 0x67, 0x84, 0x65,
+ 0x82, 0x4D, 0x83, 0x65, 0x30, 0x50, 0xA6, 0x58, 0x43, 0x06, 0x00,
+ 0x8D, 0x45, 0xA0, 0x45, 0x6A, 0x83, 0x6B, 0x06, 0x00, 0x81, 0x43,
+ 0x9C, 0x58, 0x84, 0x30, 0x90, 0x67, 0x64, 0x88, 0x64, 0x80, 0x65,
+ 0x88, 0x65, 0x82, 0x10, 0xC0, 0xEB, 0x10, 0xC0, 0x66, 0x85, 0x64,
+ 0x81, 0x17, 0x00, 0x80, 0x20, 0x0D, 0x80, 0x18, 0x0C, 0x80, 0x64,
+ 0x30, 0x60, 0x41, 0x82, 0x42, 0xB2, 0x42, 0x80, 0x40, 0x81, 0x40,
+ 0x80, 0x41, 0x80, 0x42, 0x80, 0x43, 0x83, 0x06, 0xC0, 0x88, 0x44,
+ 0x87, 0x6A, 0x83, 0x6B, 0x92, 0x44, 0x88, 0x06, 0xC8, 0x81, 0x41,
+ 0x85, 0x30, 0xA4, 0x67, 0x85, 0x65, 0x87, 0x65, 0x30, 0x60, 0x8D,
+ 0x42, 0x82, 0x40, 0x82, 0x40, 0x80, 0x41, 0x80, 0x42, 0x80, 0x43,
+ 0x83, 0x06, 0xC0, 0x88, 0x44, 0x9C, 0x44, 0x88, 0x06, 0xC8, 0x85,
+ 0x41, 0x6A, 0x83, 0x6B, 0xA0, 0x42, 0x82, 0x40, 0x6C, 0x3A, 0xA8,
+ 0x80, 0x28, 0x30, 0x70, 0x6F, 0x40, 0x14, 0x0E, 0x23, 0xC2, 0x41,
+ 0x82, 0x42, 0x00, 0xC0, 0x5D, 0x80, 0x5A, 0x80, 0x57, 0x84, 0x64,
+ 0x80, 0x55, 0x86, 0x64, 0x80, 0x65, 0x88, 0x65, 0x82, 0x54, 0x80,
+ 0x58, 0x80, 0x00, 0xC0, 0x86, 0x42, 0x82, 0x10, 0x30, 0x9C, 0x5C,
+ 0x80, 0x6E, 0x86, 0x5B, 0x80, 0x63, 0x9E, 0x59, 0x8C, 0x5E, 0x8A,
+ 0x6C, 0x80, 0x6D, 0x81, 0x5F, 0x60, 0x61, 0x88, 0x10, 0x30, 0x66,
+ 0x83, 0x6E, 0x80, 0x64, 0x87, 0x64, 0x30, 0x50, 0xD3, 0x6A, 0x6B,
+ 0xAD, 0x30, 0x94, 0x67, 0x84, 0x65, 0x82, 0x4D, 0x83, 0x65, 0x30,
+ 0x50, 0xA7, 0x43, 0x06, 0x00, 0x8D, 0x45, 0x9A, 0x6A, 0x6B, 0x45,
+ 0x85, 0x06, 0x00, 0x81, 0x43, 0x8A, 0x6F, 0x96, 0x30, 0x90, 0x67,
+ 0x64, 0x88, 0x64, 0x80, 0x65, 0x82, 0x10, 0xC0, 0x84, 0x65, 0xEF,
+ 0x10, 0xC0, 0x66, 0x85, 0x64, 0x81, 0x17, 0x00, 0x80, 0x20, 0x0D,
+ 0x80, 0x18, 0x0C, 0x80, 0x64, 0x30, 0x60, 0x41, 0x82, 0x42, 0xB2,
+ 0x42, 0x80, 0x40, 0x82, 0x40, 0x4C, 0x45, 0x92, 0x6A, 0x6B, 0x9B,
+ 0x45, 0x81, 0x4C, 0x40, 0x8C, 0x30, 0xA4, 0x67, 0x85, 0x65, 0x87,
+ 0x65, 0x30, 0x60, 0xD3, 0x6A, 0x6B, 0xAC, 0x6C, 0x32, 0xA8, 0x80,
+ 0x28, 0x30, 0x70, 0x00, 0x80, 0x40, 0x4C, 0xBD, 0x00, 0x0E, 0xBE,
+ 0x44, 0x88, 0x44, 0xBC, 0x78, 0x09, 0x00, 0x89, 0x04, 0x80, 0x80,
+ 0x02, 0x40, 0x86, 0x09, 0x00, 0x8E, 0x09, 0x00, 0x80, 0x02, 0x40,
+ 0x80, 0x04, 0x80, 0x88, 0x7D, 0x9E, 0x86, 0x09, 0x00, 0x87, 0x7A,
+ 0x00, 0x0E, 0xC3, 0x79, 0x4C, 0x40, 0xBF, 0x70, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+u8 Sequencer_iHDR_v12p12_data[] = {
+ 0x04, 0x87, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x6F, 0x40, 0x14,
+ 0x0E, 0x23, 0x82, 0x41, 0x5C, 0x54, 0x6E, 0x42, 0x00, 0xC0, 0x5D,
+ 0x80, 0x5A, 0x80, 0x57, 0x84, 0x64, 0x80, 0x55, 0x84, 0x00, 0xC4,
+ 0x10, 0x30, 0x64, 0x80, 0x65, 0x88, 0x65, 0x88, 0x30, 0x0C, 0xB0,
+ 0x5B, 0x80, 0x63, 0x8B, 0x30, 0x0C, 0xA2, 0x58, 0x87, 0x6C, 0x80,
+ 0x6D, 0x81, 0x5F, 0x60, 0x61, 0xA3, 0x59, 0x8C, 0x10, 0x30, 0x88,
+ 0x66, 0x83, 0x6E, 0x80, 0x64, 0x87, 0x64, 0x30, 0x50, 0xDA, 0x6A,
+ 0x83, 0x6B, 0xA6, 0x30, 0x94, 0x67, 0x84, 0x65, 0x82, 0x4D, 0x83,
+ 0x65, 0x30, 0x50, 0xA6, 0x58, 0x43, 0x06, 0x00, 0x8D, 0x45, 0xA0,
+ 0x45, 0x6A, 0x83, 0x6B, 0x06, 0x00, 0x81, 0x43, 0x9C, 0x58, 0x84,
+ 0x30, 0x90, 0x67, 0x64, 0x88, 0x64, 0x80, 0x65, 0x88, 0x65, 0x82,
+ 0x10, 0xC0, 0xC3, 0x10, 0xC0, 0x66, 0x85, 0x64, 0x81, 0x17, 0x00,
+ 0x80, 0x20, 0x0D, 0x80, 0x18, 0x0C, 0x80, 0x64, 0x30, 0x60, 0x41,
+ 0x82, 0x42, 0xB2, 0x42, 0x80, 0x40, 0x81, 0x40, 0x80, 0x41, 0x80,
+ 0x42, 0x80, 0x43, 0x83, 0x06, 0xC0, 0x88, 0x44, 0x87, 0x6A, 0x83,
+ 0x6B, 0x92, 0x44, 0x88, 0x06, 0xC8, 0x81, 0x41, 0x85, 0x30, 0xA4,
+ 0x67, 0x85, 0x65, 0x87, 0x65, 0x30, 0x60, 0x8D, 0x42, 0x82, 0x40,
+ 0x82, 0x40, 0x80, 0x41, 0x80, 0x42, 0x80, 0x43, 0x83, 0x06, 0xC0,
+ 0x88, 0x44, 0x9C, 0x44, 0x88, 0x06, 0xC8, 0x85, 0x41, 0x6A, 0x83,
+ 0x6B, 0xA0, 0x42, 0x82, 0x40, 0x6C, 0x3A, 0xA8, 0x80, 0x28, 0x30,
+ 0x40, 0x80, 0x41, 0x80, 0x42, 0x80, 0x43, 0x88, 0x06, 0xC0, 0x83,
+ 0x44, 0xA0, 0x44, 0x88, 0x06, 0xC8, 0x81, 0x41, 0xA6, 0x42, 0x82,
+ 0x40, 0x82, 0x40, 0x80, 0x41, 0x80, 0x42, 0x80, 0x43, 0x83, 0x06,
+ 0xC0, 0x88, 0x44, 0xA0, 0x44, 0x88, 0x06, 0xC8, 0x81, 0x41, 0xA6,
+ 0x42, 0x82, 0x40, 0x80, 0x70, 0x00, 0x6F, 0x40, 0x14, 0x0E, 0x23,
+ 0xC2, 0x41, 0x82, 0x42, 0x00, 0xC0, 0x5D, 0x80, 0x5A, 0x80, 0x57,
+ 0x84, 0x64, 0x80, 0x55, 0x86, 0x64, 0x80, 0x65, 0x88, 0x65, 0x82,
+ 0x54, 0x80, 0x58, 0x80, 0x00, 0xC0, 0x86, 0x42, 0x82, 0x10, 0x30,
+ 0x9C, 0x5C, 0x80, 0x6E, 0x86, 0x5B, 0x80, 0x63, 0x9E, 0x59, 0x8C,
+ 0x5E, 0x8A, 0x6C, 0x80, 0x6D, 0x81, 0x5F, 0x60, 0x61, 0x10, 0x30,
+ 0x88, 0x66, 0x83, 0x6E, 0x80, 0x64, 0x87, 0x64, 0x30, 0x50, 0xD3,
+ 0x6A, 0x6B, 0xAD, 0x30, 0x94, 0x67, 0x84, 0x65, 0x82, 0x4D, 0x83,
+ 0x65, 0x30, 0x50, 0xA7, 0x43, 0x06, 0x00, 0x8D, 0x45, 0x9A, 0x6A,
+ 0x6B, 0x45, 0x85, 0x06, 0x00, 0x81, 0x43, 0x8A, 0x6F, 0x96, 0x30,
+ 0x90, 0x67, 0x64, 0x88, 0x64, 0x80, 0x65, 0x82, 0x10, 0xC0, 0x84,
+ 0x65, 0xEF, 0x10, 0xC0, 0x66, 0x85, 0x64, 0x81, 0x17, 0x00, 0x80,
+ 0x20, 0x0D, 0x80, 0x18, 0x0C, 0x80, 0x64, 0x30, 0x60, 0x41, 0x82,
+ 0x42, 0xB2, 0x42, 0x80, 0x40, 0x82, 0x40, 0x4C, 0x45, 0x92, 0x6A,
+ 0x6B, 0x9B, 0x45, 0x81, 0x4C, 0x40, 0x8C, 0x30, 0xA4, 0x67, 0x85,
+ 0x65, 0x87, 0x65, 0x30, 0x60, 0xD3, 0x6A, 0x6B, 0xAC, 0x6C, 0x32,
+ 0xA8, 0x80, 0x28, 0x30, 0x70, 0x00, 0x80, 0x40, 0x4C, 0xBD, 0x00,
+ 0x0E, 0xBE, 0x44, 0x88, 0x44, 0xBC, 0x78, 0x00, 0x00,
+};
+
+static struct ar0833_reg_blob Sequencer_iHDR_v12p12 = {
+ .addr = 0x3D00,
+ .size = sizeof(Sequencer_iHDR_v12p12_data),
+ .data = Sequencer_iHDR_v12p12_data,
+};
+
+static struct ar0833_reg_blob Sequencer_Adjustment_v7p2 = {
+ .addr = 0x3D00,
+ .size = sizeof(Sequencer_Adjustment_v7p2_data),
+ .data = Sequencer_Adjustment_v7p2_data,
+};
+
+u8 Sequencer_iHDR_v7p2_data[] = {
+ 0x04, 0x88, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x6F, 0x40, 0x14,
+ 0x0E, 0x23, 0x82, 0x41, 0x5C, 0x54, 0x6E, 0x42, 0x00, 0xC0, 0x5D,
+ 0x80, 0x5A, 0x80, 0x57, 0x84, 0x64, 0x80, 0x55, 0x86, 0x64, 0x80,
+ 0x65, 0x88, 0x65, 0x84, 0x58, 0x80, 0x00, 0xC0, 0x80, 0x30, 0x0C,
+ 0x84, 0x42, 0x82, 0x10, 0x30, 0xA6, 0x5B, 0x80, 0x63, 0x8B, 0x30,
+ 0x0C, 0xA5, 0x59, 0x84, 0x6C, 0x80, 0x6D, 0x81, 0x5F, 0x60, 0x61,
+ 0x10, 0x30, 0x88, 0x66, 0x83, 0x6E, 0x80, 0x64, 0x87, 0x64, 0x30,
+ 0x50, 0xDA, 0x6A, 0x83, 0x6B, 0xA6, 0x30, 0x94, 0x67, 0x84, 0x65,
+ 0x82, 0x4D, 0x83, 0x65, 0x30, 0x50, 0xA6, 0x58, 0x43, 0x06, 0x00,
+ 0x8D, 0x45, 0xA0, 0x45, 0x6A, 0x83, 0x6B, 0x06, 0x00, 0x81, 0x43,
+ 0x9C, 0x58, 0x84, 0x30, 0x90, 0x67, 0x64, 0x88, 0x64, 0x80, 0x65,
+ 0x88, 0x65, 0x82, 0x10, 0xC0, 0xEB, 0x10, 0xC0, 0x66, 0x85, 0x64,
+ 0x81, 0x17, 0x00, 0x80, 0x20, 0x0D, 0x80, 0x18, 0x0C, 0x80, 0x64,
+ 0x30, 0x60, 0x41, 0x82, 0x42, 0xB2, 0x42, 0x80, 0x40, 0x81, 0x40,
+ 0x80, 0x41, 0x80, 0x42, 0x80, 0x43, 0x83, 0x06, 0xC0, 0x88, 0x44,
+ 0x87, 0x6A, 0x83, 0x6B, 0x92, 0x44, 0x88, 0x06, 0xC8, 0x81, 0x41,
+ 0x85, 0x30, 0xA4, 0x67, 0x85, 0x65, 0x87, 0x65, 0x30, 0x60, 0x8D,
+ 0x42, 0x82, 0x40, 0x82, 0x40, 0x80, 0x41, 0x80, 0x42, 0x80, 0x43,
+ 0x83, 0x06, 0xC0, 0x88, 0x44, 0x9C, 0x44, 0x88, 0x06, 0xC8, 0x85,
+ 0x41, 0x6A, 0x83, 0x6B, 0xA0, 0x42, 0x82, 0x40, 0x6C, 0x3A, 0xA8,
+ 0x80, 0x28, 0x30, 0x40, 0x80, 0x41, 0x80, 0x42, 0x80, 0x43, 0x88,
+ 0x06, 0xC0, 0x83, 0x44, 0xA0, 0x44, 0x88, 0x06, 0xC8, 0x81, 0x41,
+ 0xA6, 0x42, 0x82, 0x40, 0x82, 0x40, 0x80, 0x41, 0x80, 0x42, 0x80,
+ 0x43, 0x83, 0x06, 0xC0, 0x88, 0x44, 0xA0, 0x44, 0x88, 0x06, 0xC8,
+ 0x81, 0x41, 0xA6, 0x42, 0x82, 0x40, 0x80, 0x70, 0x6F, 0x40, 0x14,
+ 0x0E, 0x23, 0xC2, 0x41, 0x82, 0x42, 0x00, 0xC0, 0x5D, 0x80, 0x5A,
+ 0x80, 0x57, 0x84, 0x64, 0x80, 0x55, 0x86, 0x64, 0x80, 0x65, 0x88,
+ 0x65, 0x82, 0x54, 0x80, 0x58, 0x80, 0x00, 0xC0, 0x86, 0x42, 0x82,
+ 0x10, 0x30, 0x9C, 0x5C, 0x80, 0x6E, 0x86, 0x5B, 0x80, 0x63, 0x9E,
+ 0x59, 0x8C, 0x5E, 0x8A, 0x6C, 0x80, 0x6D, 0x81, 0x5F, 0x60, 0x61,
+ 0x10, 0x30, 0x88, 0x66, 0x83, 0x6E, 0x80, 0x64, 0x87, 0x64, 0x30,
+ 0x50, 0xD3, 0x6A, 0x6B, 0xAD, 0x30, 0x94, 0x67, 0x84, 0x65, 0x82,
+ 0x4D, 0x83, 0x65, 0x30, 0x50, 0xA7, 0x43, 0x06, 0x00, 0x8D, 0x45,
+ 0x9A, 0x6A, 0x6B, 0x45, 0x85, 0x06, 0x00, 0x81, 0x43, 0x8A, 0x6F,
+ 0x96, 0x30, 0x90, 0x67, 0x64, 0x88, 0x64, 0x80, 0x65, 0x82, 0x10,
+ 0xC0, 0x84, 0x65, 0xEF, 0x10, 0xC0, 0x66, 0x85, 0x64, 0x81, 0x17,
+ 0x00, 0x80, 0x20, 0x0D, 0x80, 0x18, 0x0C, 0x80, 0x64, 0x30, 0x60,
+ 0x41, 0x82, 0x42, 0xB2, 0x42, 0x80, 0x40, 0x82, 0x40, 0x4C, 0x45,
+ 0x92, 0x6A, 0x6B, 0x9B, 0x45, 0x81, 0x4C, 0x40, 0x8C, 0x30, 0xA4,
+ 0x67, 0x85, 0x65, 0x87, 0x65, 0x30, 0x60, 0xD3, 0x6A, 0x6B, 0xAC,
+ 0x6C, 0x32, 0xA8, 0x80, 0x28, 0x30, 0x70, 0x00, 0x80, 0x40, 0x4C,
+ 0xBD, 0x00, 0x0E, 0xBE, 0x44, 0x88, 0x44, 0xBC, 0x78,
+};
+
+static struct ar0833_reg_blob Sequencer_iHDR_v7p2 = {
+ .addr = 0x3D00,
+ .size = sizeof(Sequencer_iHDR_v7p2_data),
+ .data = Sequencer_iHDR_v7p2_data,
+};
+
+static struct ar0833_reg MipiTimings[] = {
+ {0x31B0, 0x0060},
+ {0x31B2, 0x0042},
+ {0x31B4, 0x4C36},
+ {0x31B6, 0x5218},
+ {0x31B8, 0x404A},
+ {0x31BA, 0x028A},
+ {0x31BC, 0x0008},
+ {AR0833_TABLE_WAIT_MS, 1},
+ {AR0833_TABLE_END, 0x0000},
+};
+
+enum {
+ AR0833_TBL_RESET,
+ AR0833_TBL_DEF3P,
+ AR0833_TBL_SEQ_ADJ_V7P2,
+ AR0833_TBL_SEQ_HDR_V12P12,
+ AR0833_TBL_SEQ_HDR_V7P2,
+ AR0833_TBL_MIPITM,
+ NUM_OF_SUBTBLS,
+};
+
+static void *sub_tbls[] = {
+ [AR0833_TBL_RESET] = Reset_tbl,
+ [AR0833_TBL_DEF3P] = Default_3P_tbl,
+ [AR0833_TBL_SEQ_ADJ_V7P2] = &Sequencer_Adjustment_v7p2,
+ [AR0833_TBL_SEQ_HDR_V12P12] = &Sequencer_iHDR_v12p12,
+ [AR0833_TBL_SEQ_HDR_V7P2] = &Sequencer_iHDR_v7p2,
+ [AR0833_TBL_MIPITM] = MipiTimings,
+};
+
+/*
+ * Initialize
+ * XMCLK=24000000
+ * PAUSE=1
+ * STATE= Master Clock, 292800000
+ * REG=0x301A, 0x0218, Disable Streaming
+ * LOAD=Default_3P
+ * LOAD=Sequencer_Adjustment_v7p2
+ */
+static struct ar0833_reg mode_3264x2448_30fps[] = {
+ {AR0833_TABLE_CALL, AR0833_TBL_RESET},
+ {AR0833_TABLE_CALL, AR0833_TBL_DEF3P},
+ {AR0833_TABLE_WAIT_MS, 1},
+ {AR0833_TABLE_BLOB, AR0833_TBL_SEQ_ADJ_V7P2},
+
+ /* PLL Configuration */
+ {0x0300, 0x0005}, /*VT_PIX_CLK_DIV=5 */
+ {0x0302, 0x0001}, /*VT_SYS_CLK_DIV=1 */
+ {0x0304, 0x0004}, /*PRE_PLL_CLK_DIV=4 Note: 24MHz/4=6MHz */
+ /*PLL_MULTIPLIER=122 Note: Running at 732MHz */
+ {0x0306, 0x007A},
+ {0x0308, 0x000A}, /*OP_PIX_CLK_DIV=10 */
+ {0x030A, 0x0001}, /*OP_SYS_CLK_DIV=1 */
+ {0x3064, 0x7800},
+ {AR0833_TABLE_WAIT_MS, 1},
+
+ /* LOAD=MIPI Timings */
+ {AR0833_TABLE_CALL, AR0833_TBL_MIPITM},
+
+ /* Frame Timing */
+ {0x0340, 0x0A10}, /*FRAME_LENGTH_LINES */
+ {0x0342, 0x0ECC}, /*LINE_LENGTH_PCK */
+ {0x0344, 0x0008}, /*X_ADDR_START 8 */
+ {0x0346, 0x0008}, /*Y_ADDR_START 8 */
+ {0x0348, 0x0CC7}, /*X_ADDR_END 3271 */
+ {0x034A, 0x0997}, /*Y_ADDR_END 2455 */
+ {0x034C, 0x0CC0}, /*X_OUTPUT_SIZE 3264 */
+ {0x034E, 0x0990}, /*Y_OUTPUT_SIZE 2448 */
+ {0x3040, 0x4041}, /*X_ODD_INC & Y_ODD_INC */
+ {0x0202, 0x0A01}, /*COARSE_INTEGRATION_TIME */
+ {0x305E, 0x1000}, /* gain */
+ /*Scaling Enabling: 0= disable, 1= x-dir, 2= xy-dir */
+ {0x0400, 0x0000},
+ {0x0402, 0x0000}, /*Co-Site Scaling */
+ {0x0404, 0x0010}, /*Scale_M = 16 */
+ {0x0408, 0x1010},
+ {0x040A, 0x0210},
+ {0x306E, 0x9080}, /*Data Path Select */
+ {0x301A, 0x001C}, /* Enable Streaming */
+ {AR0833_TABLE_END, 0x0000},
+};
+
+static struct ar0833_reg mode_3264x2448_HDR_30fps[] = {
+ {AR0833_TABLE_CALL, AR0833_TBL_RESET},
+ {AR0833_TABLE_CALL, AR0833_TBL_DEF3P},
+
+ {0x0300, 0x0004}, /* VT_PIX_CLK_DIV = 4 */
+ {0x0304, 0x0004},
+ {0x0306, 0x007A},
+
+ /* LOAD=MIPI Timings */
+ {AR0833_TABLE_CALL, AR0833_TBL_MIPITM},
+
+ {0x0340, 2579}, /* FLL = 2579 */
+ {0x0342, 4832}, /* LLPCK = 4832 */
+ {0x0344, 0x0008}, /*X_ADDR_START */
+ {0x0346, 0x0008}, /*Y_ADDR_START */
+ {0x0348, 0x0CC7}, /*X_ADDR_END */
+ {0x034A, 0x0997}, /*Y_ADDR_END */
+ {0x034C, 0x0CC0}, /*X_OUTPUT_SIZE */
+ {0x034E, 0x0990}, /*Y_OUTPUT_SIZE */
+ {0x0202, 2400}, /* T1 Coarse Integration */
+ {0x3088, 300}, /* T2 Coarse Integration */
+ {0x305E, 0x1000}, /* gain */
+ {0x3040, 0x4041}, /*Default read mode */
+
+ /* Disable Streaming */
+ {0x301A, 0x0218},
+ {AR0833_TABLE_WAIT_MS, 1},
+ /*LOAD=Sequencer_iHDR_v7p2 */
+ {AR0833_TABLE_BLOB, AR0833_TBL_SEQ_HDR_V12P12},
+ /* Enable iHDR readout */
+ {0x303E, 0x0001},
+ /* Other Settings
+ BLC Options need to be set to not use auto calib in iHDR */
+ {0x30C0, 0x2001},
+ {0x30C8, 0x2020},
+ /*Disable Defect Correction, check for 1DDC? -> REG= 0x31E0, 0x01F1 */
+ {0x31E0, 0x0000},
+
+ /* No3 iHDR*/
+ {0x316C, 0x8200},
+ {0x3EFE, 0x2222},
+ {0x3EE6, 0xB10C},
+ {0x3ED8, 0x7288},
+
+ {0x301A, 0x001C}, /* Enable Streaming */
+ {AR0833_TABLE_END, 0x0000},
+};
+
+/*
+ * Initialize
+ * XMCLK=24000000
+ * PAUSE=1
+ * STATE= Master Clock, 292800000
+ * REG=0x301A, 0x0218, Disable Streaming
+ * LOAD=Default_3P
+ * LOAD=Sequencer_Adjustment_v7p2
+ */
+static struct ar0833_reg mode_1920x1080_HDR_30fps[] = {
+ {AR0833_TABLE_CALL, AR0833_TBL_RESET},
+ {AR0833_TABLE_CALL, AR0833_TBL_DEF3P},
+
+ {0x0304, 0x0004},
+ {0x0306, 0x007A},
+
+ /* LOAD=MIPI Timings */
+ {AR0833_TABLE_CALL, AR0833_TBL_MIPITM},
+
+ {0x0340, 1990}, /* FLL = 2579 */
+ {0x0342, 4832}, /* LLPCK = 4832v */
+ {0x0344, 0x02A0}, /*X_ADDR_START 672 */
+ {0x0346, 0x0130}, /*Y_ADDR_START 304 */
+ {0x0348, 0x0A1F}, /*X_ADDR_END 2591 */
+ {0x034A, 0x0567}, /*Y_ADDR_END 1751 */
+ {0x034C, 0x0780}, /*X_OUTPUT_SIZE 1920 */
+ {0x034E, 0x0438}, /*Y_OUTPUT_SIZE 1080 */
+ {0x3040, 0x4041}, /*X_ODD_INC and Y_ODD_INC */
+ {0x0202, 1952}, /* T1 Coarse Integration */
+ {0x3088, 244}, /* T2 Coarse Integration */
+ {0x305E, 0x1000}, /* gain */
+
+ /* Disable Streaming */
+ {0x301A, 0x0218},
+ {AR0833_TABLE_WAIT_MS, 1},
+ {AR0833_TABLE_BLOB, AR0833_TBL_SEQ_HDR_V7P2},
+
+ {0x303E, 0x0001}, /* Enable iHDR readout */
+ /* Other Settings
+ BLC Options need to be set to not use auto calib in iHDR */
+ {0x30C0, 0x2001},
+ {0x30C8, 0x2020},
+ /*Disable Defect Correction, check for 1DDC? -> REG= 0x31E0, 0x01F1 */
+ {0x31E0, 0x0000},
+ /*BITFIELD=0x301A,0x0004,0 Disable Streaming */
+ {0x316C, 0x8200}, /* auto switch Txlo at 2x */
+ {0x3EFE, 0xC1C1}, /* Txlo Level: Txlo1=-12,Txlo0=+1 */
+ {0x3EE6, 0xB10D}, /* Txlo polarity: Txlo1-,Txlo0+ */
+ {0x3ED8, 0x7288}, /* Txlo booster setting */
+ {0x301A, 0x001C}, /* Enable Streaming */
+ {AR0833_TABLE_END, 0x0000},
+};
+
+/*
+ * Initialize
+ * XMCLK=24000000
+ * PAUSE=1
+ * STATE= Master Clock, 292800000
+ * REG=0x301A, 0x0218, Disable Streaming
+ * LOAD=Default_3P
+ * LOAD=Sequencer_Adjustment_v7p2
+ */
+static struct ar0833_reg mode_3264x1836_HDR_30fps[] = {
+ {AR0833_TABLE_CALL, AR0833_TBL_RESET},
+ {AR0833_TABLE_CALL, AR0833_TBL_DEF3P},
+
+ {0x0300, 0x0005}, /* VT_PIX_CLK_DIV = 5 */
+ {0x0304, 0x0004},
+ {0x0306, 0x007A},
+
+ /* LOAD=MIPI Timings */
+ {AR0833_TABLE_CALL, AR0833_TBL_MIPITM},
+
+ {0x0340, 1990}, /* FLL = 2579 */
+ {0x0342, 4832}, /* LLPCK = 4832 */
+ {0x0344, 0x0008}, /*X_ADDR_START */
+ {0x0346, 0x0130}, /*Y_ADDR_START */
+ {0x0348, 0x0CC7}, /*X_ADDR_END */
+ {0x034A, 0x085B}, /*Y_ADDR_END */
+ {0x034C, 0x0CC0}, /*X_OUTPUT_SIZE */
+ {0x034E, 0x072C}, /*Y_OUTPUT_SIZE */
+ {0x3040, 0x4041}, /*Default read mode */
+ {0x0202, 1952}, /* T1 Coarse Integration */
+ {0x3088, 244}, /* T2 Coarse Integration */
+ {0x305E, 0x1000}, /* gain */
+
+ /* Disable Streaming */
+ {0x301A, 0x0218},
+ {AR0833_TABLE_WAIT_MS, 1},
+ /*LOAD=Sequencer_iHDR_v7p2 */
+ {AR0833_TABLE_BLOB, AR0833_TBL_SEQ_HDR_V7P2},
+ /* Enable iHDR readout */
+ {0x303E, 0x0001},
+ /* Other Settings
+ BLC Options need to be set to not use auto calib in iHDR */
+ {0x30C0, 0x2001},
+ {0x30C8, 0x2020},
+ /*Disable Defect Correction, check for 1DDC? -> REG= 0x31E0, 0x01F1 */
+ {0x31E0, 0x0000},
+ {0x301A, 0x001C}, /* Enable Streaming */
+ {AR0833_TABLE_END, 0x0000},
+};
+
+/*
+ * Initialize
+ * XMCLK=24000000
+ * PAUSE=1
+ * STATE= Master Clock, 292800000
+ * REG=0x301A, 0x0218, Disable Streaming
+ * LOAD=Default_3P
+ * LOAD=Sequencer_Adjustment_v7p2
+ */
+static struct ar0833_reg mode_1920x1080_30fps[] = {
+ {AR0833_TABLE_CALL, AR0833_TBL_RESET},
+ {AR0833_TABLE_CALL, AR0833_TBL_DEF3P},
+ {AR0833_TABLE_WAIT_MS, 1},
+ {AR0833_TABLE_BLOB, AR0833_TBL_SEQ_ADJ_V7P2},
+
+ /*PLL Configuration */
+ {0x0300, 0x0005}, /*VT_PIX_CLK_DIV=5 */
+ {0x0302, 0x0001}, /*VT_SYS_CLK_DIV=1 */
+ {0x0304, 0x0004}, /*PRE_PLL_CLK_DIV=4 Note: 24MHz/4=6MHz */
+ {0x0306, 0x007A}, /*PLL_MULTIPLIER=122 Note: Running at 732MHz */
+ {0x0308, 0x000A}, /*OP_PIX_CLK_DIV=10 */
+ {0x030A, 0x0001}, /*OP_SYS_CLK_DIV=1 */
+ {0x3064, 0x7800},
+ {AR0833_TABLE_WAIT_MS, 1},
+
+ /*LOAD=MIPI Timings */
+ {AR0833_TABLE_CALL, AR0833_TBL_MIPITM},
+
+ {0x0340, 0x079D}, /*FRAME_LENGTH_LINES */
+ {0x0342, 0x139E}, /*LINE_LENGTH_PCK */
+ {0x0344, 0x0008}, /*X_ADDR_START */
+ {0x0346, 0x0130}, /*Y_ADDR_START */
+ {0x0348, 0x0CC7}, /*X_ADDR_END */
+ {0x034A, 0x085B}, /*Y_ADDR_END */
+ {0x034C, 0x0780}, /*X_OUTPUT_SIZE */
+ {0x034E, 0x0438}, /*Y_OUTPUT_SIZE */
+ {0x3040, 0x4041}, /*X_ODD_INC & Y_ODD_INC */
+ {0x0202, 0x0700}, /*COARSE_INTEGRATION_TIME */
+ {0x305E, 0x1000}, /* gain */
+ /*Scaling Enabling: 0= disable, 1= x-dir, 2= xy-dir */
+ {0x0400, 0x0002},
+ {0x0402, 0x0000}, /*Co-Site Scaling */
+ {0x0404, 0x001A}, /*Scale_M = 16 */
+ {0x0408, 0x0B0C},
+ {0x040A, 0x018C},
+ {0x306E, 0x9090}, /*Data Path Select */
+ {0x301A, 0x001C}, /* Enable Streaming */
+ {AR0833_TABLE_END, 0x0000},
+};
+
+/*
+ * Initialize
+ * XMCLK=24000000
+ * PAUSE=1
+ * STATE= Master Clock, 292800000
+ * REG=0x301A, 0x0218, Disable Streaming
+ * LOAD=Default_3P
+ * LOAD=Sequencer_Adjustment_v7p2
+ */
+static struct ar0833_reg mode_3264x1836_30fps[] = {
+ {AR0833_TABLE_CALL, AR0833_TBL_RESET},
+ {AR0833_TABLE_CALL, AR0833_TBL_DEF3P},
+ {AR0833_TABLE_WAIT_MS, 1},
+ {AR0833_TABLE_BLOB, AR0833_TBL_SEQ_ADJ_V7P2},
+
+ /*PLL Configuration */
+ {0x0300, 0x0005}, /*VT_PIX_CLK_DIV=5 */
+ {0x0302, 0x0001}, /*VT_SYS_CLK_DIV=1 */
+ {0x0304, 0x0004}, /*PRE_PLL_CLK_DIV=4 Note: 24MHz/4=6MHz */
+ {0x0306, 0x007A}, /*PLL_MULTIPLIER=122 Note: Running at 732MHz */
+ {0x0308, 0x000A}, /*OP_PIX_CLK_DIV=10 */
+ {0x030A, 0x0001}, /*OP_SYS_CLK_DIV=1 */
+ {0x3064, 0x7800},
+ {AR0833_TABLE_WAIT_MS, 1},
+
+ {AR0833_TABLE_CALL, AR0833_TBL_MIPITM},
+
+ /*Frame Timing */
+ {0x0340, 0x079D}, /*FRAME_LENGTH_LINES */
+ {0x0342, 0x139E}, /*LINE_LENGTH_PCK */
+ {0x0344, 0x0008}, /*X_ADDR_START */
+ {0x0346, 0x0130}, /*Y_ADDR_START */
+ {0x0348, 0x0CC7}, /*X_ADDR_END */
+ {0x034A, 0x085B}, /*Y_ADDR_END */
+ {0x034C, 0x0CC0}, /*X_OUTPUT_SIZE */
+ {0x034E, 0x072C}, /*Y_OUTPUT_SIZE */
+ {0x3040, 0x4041}, /*X_ODD_INC & Y_ODD_INC */
+ {0x0202, 0x0700}, /*COARSE_INTEGRATION_TIME */
+ {0x305E, 0x1000}, /* gain */
+ /*Scaling Enabling: 0= disable, 1= x-dir, 2= xy-dir */
+ {0x0400, 0x0000},
+ {0x0402, 0x0000}, /*Co-Site Scaling */
+ {0x0404, 0x0010}, /*Scale_M = 16 */
+ {0x0408, 0x1010},
+ {0x040A, 0x0210},
+ {0x306E, 0x9080}, /*Data Path Select */
+ {0x301A, 0x001C}, /* Enable Streaming */
+ {AR0833_TABLE_END, 0x0000},
+};
diff --git a/drivers/media/video/tegra/dw9718.c b/drivers/media/video/tegra/dw9718.c
new file mode 100644
index 000000000000..c2044ae3ac63
--- /dev/null
+++ b/drivers/media/video/tegra/dw9718.c
@@ -0,0 +1,1077 @@
+/*
+ * dw9718.c - dw9718 focuser driver
+ *
+ * Copyright (C) 2013, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ */
+/* Implementation
+ * --------------
+ * The board level details about the device need to be provided in the board
+ * file with the <device>_platform_data structure.
+ * Standard among NVC kernel drivers in this structure is:
+ * .cfg = Use the NVC_CFG_ defines that are in nvc.h.
+ * Descriptions of the configuration options are with the defines.
+ * This value is typically 0.
+ * .num = The number of the instance of the device. This should start at 1 and
+ * and increment for each device on the board. This number will be
+ * appended to the MISC driver name, Example: /dev/focuser.1
+ * If not used or 0, then nothing is appended to the name.
+ * .sync = If there is a need to synchronize two devices, then this value is
+ * the number of the device instance (.num above) this device is to
+ * sync to. For example:
+ * Device 1 platform entries =
+ * .num = 1,
+ * .sync = 2,
+ * Device 2 platfrom entries =
+ * .num = 2,
+ * .sync = 1,
+ * The above example sync's device 1 and 2.
+ * To disable sync, set .sync = 0. Note that the .num = 0 device is not
+ * allowed to be synced to.
+ * This is typically used for stereo applications.
+ * .dev_name = The MISC driver name the device registers as. If not used,
+ * then the part number of the device is used for the driver name.
+ * If using the NVC user driver then use the name found in this
+ * driver under _default_pdata.
+ * .gpio_count = The ARRAY_SIZE of the nvc_gpio_pdata table.
+ * .gpio = A pointer to the nvc_gpio_pdata structure's platform GPIO data.
+ * The GPIO mechanism works by cross referencing the .gpio_type key
+ * among the nvc_gpio_pdata GPIO data and the driver's nvc_gpio_init
+ * GPIO data to build a GPIO table the driver can use. The GPIO's
+ * defined in the device header file's _gpio_type enum are the
+ * gpio_type keys for the nvc_gpio_pdata and nvc_gpio_init structures.
+ * These need to be present in the board file's nvc_gpio_pdata
+ * structure for the GPIO's that are used.
+ * The driver's GPIO logic uses assert/deassert throughout until the
+ * low level _gpio_wr/rd calls where the .assert_high is used to
+ * convert the value to the correct signal level.
+ * See the GPIO notes in nvc.h for additional information.
+ *
+ * The following is specific to NVC kernel focus drivers:
+ * .nvc = Pointer to the nvc_focus_nvc structure. This structure needs to
+ * be defined and populated if overriding the driver defaults.
+ * .cap = Pointer to the nvc_focus_cap structure. This structure needs to
+ * be defined and populated if overriding the driver defaults.
+ *
+ * The following is specific to this NVC kernel focus driver:
+ * .info = Pointer to the dw9718_pdata_info structure. This structure does
+ * not need to be defined and populated unless overriding ROM data.
+ *
+ * Power Requirements:
+ * The device's header file defines the voltage regulators needed with the
+ * enumeration <device>_vreg. The order these are enumerated is the order
+ * the regulators will be enabled when powering on the device. When the
+ * device is powered off the regulators are disabled in descending order.
+ * The <device>_vregs table in this driver uses the nvc_regulator_init
+ * structure to define the regulator ID strings that go with the regulators
+ * defined with <device>_vreg. These regulator ID strings (or supply names)
+ * will be used in the regulator_get function in the _vreg_init function.
+ * The board power file and <device>_vregs regulator ID strings must match.
+ */
+
+#include <linux/fs.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include <linux/i2c.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include <linux/list.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <media/dw9718.h>
+
+#define ENABLE_DEBUGFS_INTERFACE
+
+#define dw9718_ID 0x04
+#define dw9718_FOCAL_LENGTH_FLOAT (4.570f)
+#define dw9718_FNUMBER_FLOAT (2.8f)
+#define dw9718_FOCAL_LENGTH (0x40923D71) /* 4.570f */
+#define dw9718_FNUMBER (0x40333333) /* 2.8f */
+#define dw9718_SLEW_RATE 0x0060
+#define dw9718_ACTUATOR_RANGE 1023
+#define dw9718_SETTLETIME 30
+#define dw9718_FOCUS_MACRO 620
+#define dw9718_FOCUS_INFINITY 70
+#define dw9718_POS_LOW_DEFAULT 0
+#define dw9718_POS_HIGH_DEFAULT 1023
+#define dw9718_POS_CLAMP 0x03ff
+/* Need to decide exact value of VCM_THRESHOLD and its use */
+/* define dw9718_VCM_THRESHOLD 20 */
+
+struct dw9718_info {
+ atomic_t in_use;
+ struct i2c_client *i2c_client;
+ struct dw9718_platform_data *pdata;
+ struct miscdevice miscdev;
+ struct list_head list;
+ int pwr_dev;
+ struct dw9718_power_rail power;
+ int status;
+ u32 cur_pos;
+ u8 s_mode;
+ bool reset_flag;
+ struct dw9718_info *s_info;
+ struct nvc_focus_nvc nvc;
+ struct nvc_focus_cap cap;
+ struct nv_focuser_config nv_config;
+};
+
+/**
+ * The following are default values
+ */
+static struct nvc_focus_cap dw9718_default_cap = {
+ .version = NVC_FOCUS_CAP_VER2,
+ .slew_rate = dw9718_SLEW_RATE,
+ .actuator_range = dw9718_ACTUATOR_RANGE,
+ .settle_time = dw9718_SETTLETIME,
+ .focus_macro = dw9718_FOCUS_MACRO,
+ .focus_infinity = dw9718_FOCUS_INFINITY,
+ .focus_hyper = dw9718_FOCUS_INFINITY,
+};
+
+static struct nvc_focus_nvc dw9718_default_nvc = {
+ .focal_length = dw9718_FOCAL_LENGTH,
+ .fnumber = dw9718_FNUMBER,
+ .max_aperature = dw9718_FNUMBER,
+};
+
+static struct dw9718_platform_data dw9718_default_pdata = {
+ .cfg = 0,
+ .num = 0,
+ .sync = 0,
+ .dev_name = "focuser",
+};
+static LIST_HEAD(dw9718_info_list);
+static DEFINE_SPINLOCK(dw9718_spinlock);
+
+static int dw9718_i2c_wr8(struct dw9718_info *info, u8 reg, u8 val)
+{
+ struct i2c_msg msg;
+ u8 buf[2];
+ buf[0] = reg;
+ buf[1] = val;
+ msg.addr = info->i2c_client->addr;
+ msg.flags = 0;
+ msg.len = 2;
+ msg.buf = &buf[0];
+ if (i2c_transfer(info->i2c_client->adapter, &msg, 1) != 1)
+ return -EIO;
+ return 0;
+}
+
+static int dw9718_i2c_wr16(struct dw9718_info *info, u8 reg, u16 val)
+{
+ struct i2c_msg msg;
+ u8 buf[3];
+ buf[0] = reg;
+ buf[1] = (u8)(val >> 8);
+ buf[2] = (u8)(val & 0xff);
+ msg.addr = info->i2c_client->addr;
+ msg.flags = 0;
+ msg.len = 3;
+ msg.buf = &buf[0];
+ if (i2c_transfer(info->i2c_client->adapter, &msg, 1) != 1)
+ return -EIO;
+ return 0;
+}
+
+/**
+ * Below are device specific functions.
+ */
+static int dw9718_position_wr(struct dw9718_info *info, s32 position)
+{
+ int err;
+
+ dev_dbg(&info->i2c_client->dev, "%s %d\n", __func__, position);
+ position &= dw9718_POS_CLAMP;
+ err = dw9718_i2c_wr16(info, DW9718_VCM_CODE_MSB, position);
+ if (!err)
+ info->cur_pos = position;
+ else
+ dev_err(&info->i2c_client->dev, "%s: ERROR set position %d",
+ __func__, position);
+ return err;
+}
+
+int dw9718_set_arc_mode(struct dw9718_info *info)
+{
+ int err;
+ u32 sr = info->nv_config.slew_rate;
+
+ dev_dbg(&info->i2c_client->dev, "%s %x\n", __func__, sr);
+ /* set ARC enable */
+ err = dw9718_i2c_wr8(info, DW9718_CONTROL, (sr >> 16) & 0xFF);
+ if (err) {
+ dev_err(&info->i2c_client->dev,
+ "%s: CONTROL reg write failed\n", __func__);
+ goto set_arc_mode_done;
+ }
+ usleep_range(80, 100);
+
+ /* set the ARC RES2 */
+ err = dw9718_i2c_wr8(info, DW9718_SWITCH_MODE, (sr >> 8) & 0xFF);
+ if (err) {
+ dev_err(&info->i2c_client->dev,
+ "%s: MODE write failed\n", __func__);
+ goto set_arc_mode_done;
+ }
+
+ err = dw9718_i2c_wr8(info, DW9718_SACT, sr & 0XFF);
+ if (err) {
+ dev_err(&info->i2c_client->dev,
+ "%s: RES write failed\n", __func__);
+ goto set_arc_mode_done;
+ }
+
+ err = dw9718_position_wr(info, 0);
+
+set_arc_mode_done:
+ return err;
+}
+
+static int dw9718_pm_wr(struct dw9718_info *info, int pwr)
+{
+ int err = 0;
+ if ((info->pdata->cfg & (NVC_CFG_OFF2STDBY | NVC_CFG_BOOT_INIT)) &&
+ (pwr == NVC_PWR_OFF || pwr == NVC_PWR_STDBY_OFF))
+ pwr = NVC_PWR_STDBY;
+
+ if (pwr == info->pwr_dev)
+ return 0;
+
+ switch (pwr) {
+ case NVC_PWR_OFF_FORCE:
+ case NVC_PWR_OFF:
+ if (info->pdata && info->pdata->power_off)
+ info->pdata->power_off(&info->power);
+ break;
+ case NVC_PWR_STDBY_OFF:
+ case NVC_PWR_STDBY:
+ if (info->pdata && info->pdata->power_off)
+ info->pdata->power_off(&info->power);
+ break;
+ case NVC_PWR_COMM:
+ case NVC_PWR_ON:
+ if (info->pdata && info->pdata->power_on)
+ info->pdata->power_on(&info->power);
+ dw9718_set_arc_mode(info);
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+
+ if (err < 0) {
+ dev_err(&info->i2c_client->dev, "%s err %d\n", __func__, err);
+ pwr = NVC_PWR_ERR;
+ }
+
+ info->pwr_dev = pwr;
+ dev_dbg(&info->i2c_client->dev, "%s pwr_dev=%d\n", __func__,
+ info->pwr_dev);
+
+ return err;
+}
+
+static int dw9718_power_put(struct dw9718_power_rail *pw)
+{
+ if (unlikely(!pw))
+ return -EFAULT;
+
+ if (likely(pw->vdd))
+ regulator_put(pw->vdd);
+
+ if (likely(pw->vdd_i2c))
+ regulator_put(pw->vdd_i2c);
+
+ pw->vdd = NULL;
+ pw->vdd_i2c = NULL;
+
+ return 0;
+}
+
+static int dw9718_regulator_get(struct dw9718_info *info,
+ struct regulator **vreg, char vreg_name[])
+{
+ struct regulator *reg = NULL;
+ int err = 0;
+
+ reg = regulator_get(&info->i2c_client->dev, vreg_name);
+ if (unlikely(IS_ERR(reg))) {
+ dev_err(&info->i2c_client->dev, "%s %s ERR: %d\n",
+ __func__, vreg_name, (int)reg);
+ err = PTR_ERR(reg);
+ reg = NULL;
+ } else
+ dev_dbg(&info->i2c_client->dev, "%s: %s\n",
+ __func__, vreg_name);
+
+ *vreg = reg;
+ return err;
+}
+
+static int dw9718_power_get(struct dw9718_info *info)
+{
+ struct dw9718_power_rail *pw = &info->power;
+
+ dw9718_regulator_get(info, &pw->vdd, "vdd");
+ dw9718_regulator_get(info, &pw->vdd_i2c, "vdd_i2c");
+
+ return 0;
+}
+
+static int dw9718_pm_dev_wr(struct dw9718_info *info, int pwr)
+{
+ if (pwr < info->pwr_dev)
+ pwr = info->pwr_dev;
+ return dw9718_pm_wr(info, pwr);
+}
+
+static void dw9718_pm_exit(struct dw9718_info *info)
+{
+ dw9718_pm_wr(info, NVC_PWR_OFF_FORCE);
+ dw9718_power_put(&info->power);
+}
+
+static int dw9718_reset(struct dw9718_info *info, u32 level)
+{
+ int err = 0;
+
+ if (level == NVC_RESET_SOFT) {
+ err = dw9718_i2c_wr8(info, DW9718_POWER_DN, 0x01);
+ usleep_range(200, 220);
+ err |= dw9718_i2c_wr8(info, DW9718_POWER_DN, 0x00);
+ usleep_range(100, 120);
+ } else
+ err = dw9718_pm_wr(info, NVC_PWR_OFF_FORCE);
+
+ return err;
+}
+
+static void dw9718_get_focuser_capabilities(struct dw9718_info *info)
+{
+ memset(&info->nv_config, 0, sizeof(info->nv_config));
+
+ dev_dbg(&info->i2c_client->dev, "%s\n", __func__);
+ info->nv_config.focal_length = info->nvc.focal_length;
+ info->nv_config.fnumber = info->nvc.fnumber;
+ info->nv_config.max_aperture = info->nvc.fnumber;
+ info->nv_config.range_ends_reversed = 0;
+
+ info->nv_config.pos_working_low = info->cap.focus_infinity;
+ info->nv_config.pos_working_high = info->cap.focus_macro;
+ info->nv_config.pos_actual_low = dw9718_POS_LOW_DEFAULT;
+ info->nv_config.pos_actual_high = dw9718_POS_HIGH_DEFAULT;
+
+ info->nv_config.slew_rate = info->cap.slew_rate;
+ info->nv_config.circle_of_confusion = -1;
+ info->nv_config.num_focuser_sets = 1;
+ info->nv_config.focuser_set[0].macro = info->cap.focus_macro;
+ info->nv_config.focuser_set[0].hyper = info->cap.focus_hyper;
+ info->nv_config.focuser_set[0].inf = info->cap.focus_infinity;
+ info->nv_config.focuser_set[0].settle_time = info->cap.settle_time;
+}
+
+static int dw9718_set_focuser_capabilities(struct dw9718_info *info,
+ struct nvc_param *params)
+{
+ dev_dbg(&info->i2c_client->dev, "%s\n", __func__);
+ if (copy_from_user(&info->nv_config,
+ (const void __user *)params->p_value,
+ sizeof(struct nv_focuser_config))) {
+ dev_err(&info->i2c_client->dev,
+ "%s Error: copy_from_user bytes %d\n",
+ __func__, sizeof(struct nv_focuser_config));
+ return -EFAULT;
+ }
+
+ /* set pre-set value, as currently ODM sets incorrect value */
+ info->cap.settle_time = dw9718_SETTLETIME;
+
+ dev_dbg(&info->i2c_client->dev,
+ "%s: copy_from_user bytes %d info->cap.settle_time %d\n",
+ __func__, sizeof(struct nv_focuser_config),
+ info->cap.settle_time);
+
+ return 0;
+}
+
+static int dw9718_param_rd(struct dw9718_info *info, unsigned long arg)
+{
+ struct nvc_param params;
+ const void *data_ptr = NULL;
+ u32 data_size = 0;
+
+ dev_dbg(&info->i2c_client->dev, "%s %lx\n", __func__, arg);
+ if (copy_from_user(&params,
+ (const void __user *)arg,
+ sizeof(struct nvc_param))) {
+ dev_err(&info->i2c_client->dev, "%s %d copy_from_user err\n",
+ __func__, __LINE__);
+ return -EFAULT;
+ }
+ if (info->s_mode == NVC_SYNC_SLAVE)
+ info = info->s_info;
+ switch (params.param) {
+ case NVC_PARAM_LOCUS:
+ data_ptr = &info->cur_pos;
+ data_size = sizeof(info->cur_pos);
+ dev_dbg(&info->i2c_client->dev, "%s LOCUS: %d\n",
+ __func__, info->cur_pos);
+ break;
+ case NVC_PARAM_FOCAL_LEN:
+ info->nvc.focal_length = dw9718_FOCAL_LENGTH;
+ data_ptr = &info->nvc.focal_length;
+ data_size = sizeof(info->nvc.focal_length);
+ break;
+ case NVC_PARAM_MAX_APERTURE:
+ data_ptr = &info->nvc.max_aperature;
+ data_size = sizeof(info->nvc.max_aperature);
+ dev_dbg(&info->i2c_client->dev, "%s MAX_APERTURE: %x\n",
+ __func__, info->nvc.max_aperature);
+ break;
+ case NVC_PARAM_FNUMBER:
+ data_ptr = &info->nvc.fnumber;
+ data_size = sizeof(info->nvc.fnumber);
+ dev_dbg(&info->i2c_client->dev, "%s FNUMBER: %u\n",
+ __func__, info->nvc.fnumber);
+ break;
+ case NVC_PARAM_CAPS:
+ /* send back just what's requested or our max size */
+ dw9718_get_focuser_capabilities(info);
+ data_ptr = &info->nv_config;
+ data_size = sizeof(info->nv_config);
+ dev_err(&info->i2c_client->dev, "%s CAPS\n", __func__);
+ break;
+ case NVC_PARAM_STS:
+ data_ptr = &info->status;
+ data_size = sizeof(info->status);
+ dev_dbg(&info->i2c_client->dev, "%s\n", __func__);
+ break;
+ case NVC_PARAM_STEREO:
+ data_ptr = &info->s_mode;
+ data_size = sizeof(info->s_mode);
+ dev_err(&info->i2c_client->dev, "%s STEREO: %d\n", __func__,
+ info->s_mode);
+ break;
+ default:
+ dev_err(&info->i2c_client->dev,
+ "%s unsupported parameter: %d\n",
+ __func__, params.param);
+ return -EINVAL;
+ }
+ if (params.sizeofvalue < data_size) {
+ dev_err(&info->i2c_client->dev,
+ "%s data size mismatch %d != %d Param: %d\n",
+ __func__, params.sizeofvalue, data_size, params.param);
+ return -EINVAL;
+ }
+ if (copy_to_user((void __user *)params.p_value, data_ptr, data_size)) {
+ dev_err(&info->i2c_client->dev, "%s copy_to_user err line %d\n",
+ __func__, __LINE__);
+ return -EFAULT;
+ }
+ return 0;
+}
+
+static int dw9718_param_wr_s(struct dw9718_info *info,
+ struct nvc_param *params, s32 s32val)
+{
+ int err = 0;
+
+ switch (params->param) {
+ case NVC_PARAM_LOCUS:
+ dev_dbg(&info->i2c_client->dev, "%s LOCUS: %d\n",
+ __func__, s32val);
+ err = dw9718_position_wr(info, s32val);
+ break;
+ case NVC_PARAM_RESET:
+ err = dw9718_reset(info, s32val);
+ dev_dbg(&info->i2c_client->dev, "%s RESET\n", __func__);
+ break;
+ case NVC_PARAM_SELF_TEST:
+ dev_dbg(&info->i2c_client->dev, "%s SELF_TEST\n", __func__);
+ break;
+ default:
+ dev_dbg(&info->i2c_client->dev,
+ "%s unsupported parameter: %d\n",
+ __func__, params->param);
+ err = -EINVAL;
+ break;
+ }
+
+ if (err)
+ dev_err(&info->i2c_client->dev, "ERROR! %d\n", err);
+ return err;
+}
+
+static int dw9718_param_wr(struct dw9718_info *info, unsigned long arg)
+{
+ struct nvc_param params;
+ u8 u8val;
+ s32 s32val;
+ int err = 0;
+ if (copy_from_user(&params, (const void __user *)arg,
+ sizeof(struct nvc_param))) {
+ dev_err(&info->i2c_client->dev,
+ "%s copy_from_user err line %d\n",
+ __func__, __LINE__);
+ return -EFAULT;
+ }
+ if (copy_from_user(&s32val,
+ (const void __user *)params.p_value, sizeof(s32val))) {
+ dev_err(&info->i2c_client->dev, "%s %d copy_from_user err\n",
+ __func__, __LINE__);
+ return -EFAULT;
+ }
+ u8val = (u8)s32val;
+ /* parameters independent of sync mode */
+ switch (params.param) {
+ case NVC_PARAM_STEREO:
+ dev_dbg(&info->i2c_client->dev, "%s STEREO: %d\n",
+ __func__, u8val);
+ if (u8val == info->s_mode)
+ return 0;
+ switch (u8val) {
+ case NVC_SYNC_OFF:
+ info->s_mode = u8val;
+ break;
+ case NVC_SYNC_MASTER:
+ info->s_mode = u8val;
+ break;
+ case NVC_SYNC_SLAVE:
+ if (info->s_info != NULL) {
+ /* default slave lens position */
+ err = dw9718_position_wr(info->s_info,
+ info->s_info->cap.focus_infinity);
+ if (!err) {
+ info->s_mode = u8val;
+ info->s_info->s_mode = u8val;
+ } else {
+ if (info->s_mode != NVC_SYNC_STEREO)
+ dw9718_pm_wr(info->s_info,
+ NVC_PWR_OFF);
+ err = -EIO;
+ }
+ } else {
+ err = -EINVAL;
+ }
+ break;
+ case NVC_SYNC_STEREO:
+ if (info->s_info != NULL) {
+ /* sync power */
+ info->s_info->pwr_dev = info->pwr_dev;
+ /* move slave lens to master position */
+ err = dw9718_position_wr(info->s_info,
+ (s32)info->cur_pos);
+ if (!err) {
+ info->s_mode = u8val;
+ info->s_info->s_mode = u8val;
+ } else {
+ if (info->s_mode != NVC_SYNC_SLAVE)
+ dw9718_pm_wr(info->s_info,
+ NVC_PWR_OFF);
+ err = -EIO;
+ }
+ } else {
+ err = -EINVAL;
+ }
+ break;
+ default:
+ err = -EINVAL;
+ }
+ if (info->pdata->cfg & NVC_CFG_NOERR)
+ return 0;
+ return err;
+
+ case NVC_PARAM_CAPS:
+ if (dw9718_set_focuser_capabilities(info, &params)) {
+ dev_err(&info->i2c_client->dev,
+ "%s: Error: copy_from_user bytes %d\n",
+ __func__, params.sizeofvalue);
+ return -EFAULT;
+ }
+ return 0;
+
+ default:
+ /* parameters dependent on sync mode */
+ switch (info->s_mode) {
+ case NVC_SYNC_OFF:
+ case NVC_SYNC_MASTER:
+ return dw9718_param_wr_s(info, &params, s32val);
+ case NVC_SYNC_SLAVE:
+ return dw9718_param_wr_s(info->s_info, &params, s32val);
+ case NVC_SYNC_STEREO:
+ err = dw9718_param_wr_s(info, &params, s32val);
+ if (!(info->pdata->cfg & NVC_CFG_SYNC_I2C_MUX))
+ err |= dw9718_param_wr_s(info->s_info,
+ &params, s32val);
+ return err;
+ default:
+ dev_err(&info->i2c_client->dev, "%s %d internal err\n",
+ __func__, __LINE__);
+ return -EINVAL;
+ }
+ }
+}
+
+static long dw9718_ioctl(struct file *file,
+ unsigned int cmd,
+ unsigned long arg)
+{
+ struct dw9718_info *info = file->private_data;
+ int pwr;
+ int err = 0;
+ switch (cmd) {
+ case NVC_IOCTL_PARAM_WR:
+ dw9718_pm_dev_wr(info, NVC_PWR_ON);
+ err = dw9718_param_wr(info, arg);
+ dw9718_pm_dev_wr(info, NVC_PWR_OFF);
+ return err;
+ case NVC_IOCTL_PARAM_RD:
+ dw9718_pm_dev_wr(info, NVC_PWR_ON);
+ err = dw9718_param_rd(info, arg);
+ dw9718_pm_dev_wr(info, NVC_PWR_OFF);
+ return err;
+ case NVC_IOCTL_PWR_WR:
+ /* This is a Guaranteed Level of Service (GLOS) call */
+ pwr = (int)arg * 2;
+ dev_dbg(&info->i2c_client->dev, "%s PWR_WR: %d\n",
+ __func__, pwr);
+ err = dw9718_pm_dev_wr(info, pwr);
+ return err;
+ case NVC_IOCTL_PWR_RD:
+ if (info->s_mode == NVC_SYNC_SLAVE)
+ pwr = info->s_info->pwr_dev;
+ else
+ pwr = info->pwr_dev;
+ dev_dbg(&info->i2c_client->dev, "%s PWR_RD: %d\n",
+ __func__, pwr);
+ if (copy_to_user((void __user *)arg,
+ (const void *)&pwr, sizeof(pwr))) {
+ dev_err(&info->i2c_client->dev,
+ "%s copy_to_user err line %d\n",
+ __func__, __LINE__);
+ return -EFAULT;
+ }
+ return 0;
+ default:
+ dev_dbg(&info->i2c_client->dev, "%s unsupported ioctl: %x\n",
+ __func__, cmd);
+ }
+ return -EINVAL;
+}
+
+
+static void dw9718_sdata_init(struct dw9718_info *info)
+{
+ /* set defaults */
+ memcpy(&info->nvc, &dw9718_default_nvc, sizeof(info->nvc));
+ memcpy(&info->cap, &dw9718_default_cap, sizeof(info->cap));
+
+ /* set overrides if any */
+ if (info->pdata->nvc) {
+ if (info->pdata->nvc->fnumber)
+ info->nvc.fnumber = info->pdata->nvc->fnumber;
+ if (info->pdata->nvc->focal_length)
+ info->nvc.focal_length = info->pdata->nvc->focal_length;
+ if (info->pdata->nvc->max_aperature)
+ info->nvc.max_aperature =
+ info->pdata->nvc->max_aperature;
+ }
+
+ if (info->pdata->cap) {
+ if (info->pdata->cap->actuator_range)
+ info->cap.actuator_range =
+ info->pdata->cap->actuator_range;
+ if (info->pdata->cap->settle_time)
+ info->cap.settle_time = info->pdata->cap->settle_time;
+ if (info->pdata->cap->slew_rate)
+ info->cap.slew_rate = info->pdata->cap->slew_rate;
+ if (info->pdata->cap->focus_macro)
+ info->cap.focus_macro = info->pdata->cap->focus_macro;
+ if (info->pdata->cap->focus_hyper)
+ info->cap.focus_hyper = info->pdata->cap->focus_hyper;
+ if (info->pdata->cap->focus_infinity)
+ info->cap.focus_infinity =
+ info->pdata->cap->focus_infinity;
+ }
+}
+
+static int dw9718_sync_en(unsigned num, unsigned sync)
+{
+ struct dw9718_info *master = NULL;
+ struct dw9718_info *slave = NULL;
+ struct dw9718_info *pos = NULL;
+ rcu_read_lock();
+ list_for_each_entry_rcu(pos, &dw9718_info_list, list) {
+ if (pos->pdata->num == num) {
+ master = pos;
+ break;
+ }
+ }
+ pos = NULL;
+ list_for_each_entry_rcu(pos, &dw9718_info_list, list) {
+ if (pos->pdata->num == sync) {
+ slave = pos;
+ break;
+ }
+ }
+ rcu_read_unlock();
+ if (master != NULL)
+ master->s_info = NULL;
+ if (slave != NULL)
+ slave->s_info = NULL;
+ if (!sync)
+ return 0; /* no err if sync disabled */
+ if (num == sync)
+ return -EINVAL; /* err if sync instance is itself */
+ if ((master != NULL) && (slave != NULL)) {
+ master->s_info = slave;
+ slave->s_info = master;
+ }
+ return 0;
+}
+
+static int dw9718_sync_dis(struct dw9718_info *info)
+{
+ if (info->s_info != NULL) {
+ info->s_info->s_mode = 0;
+ info->s_info->s_info = NULL;
+ info->s_mode = 0;
+ info->s_info = NULL;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int dw9718_open(struct inode *inode, struct file *file)
+{
+ struct dw9718_info *info = NULL;
+ struct dw9718_info *pos = NULL;
+ int err;
+ rcu_read_lock();
+ list_for_each_entry_rcu(pos, &dw9718_info_list, list) {
+ if (pos->miscdev.minor == iminor(inode)) {
+ info = pos;
+ break;
+ }
+ }
+ rcu_read_unlock();
+ if (!info)
+ return -ENODEV;
+ err = dw9718_sync_en(info->pdata->num, info->pdata->sync);
+ if (err == -EINVAL)
+ dev_err(&info->i2c_client->dev,
+ "%s err: invalid num (%u) and sync (%u) instance\n",
+ __func__, info->pdata->num, info->pdata->sync);
+ if (atomic_xchg(&info->in_use, 1))
+ return -EBUSY;
+ if (info->s_info != NULL) {
+ if (atomic_xchg(&info->s_info->in_use, 1))
+ return -EBUSY;
+ }
+ file->private_data = info;
+ dw9718_pm_dev_wr(info, NVC_PWR_ON);
+ dw9718_position_wr(info, info->cap.focus_infinity);
+ dw9718_pm_dev_wr(info, NVC_PWR_OFF);
+ dev_dbg(&info->i2c_client->dev, "%s\n", __func__);
+
+ return 0;
+}
+
+static int dw9718_release(struct inode *inode, struct file *file)
+{
+ struct dw9718_info *info = file->private_data;
+ dev_dbg(&info->i2c_client->dev, "%s\n", __func__);
+ dw9718_pm_wr(info, NVC_PWR_OFF);
+ file->private_data = NULL;
+ WARN_ON(!atomic_xchg(&info->in_use, 0));
+ if (info->s_info != NULL)
+ WARN_ON(!atomic_xchg(&info->s_info->in_use, 0));
+ dw9718_sync_dis(info);
+ return 0;
+}
+
+static const struct file_operations dw9718_fileops = {
+ .owner = THIS_MODULE,
+ .open = dw9718_open,
+ .unlocked_ioctl = dw9718_ioctl,
+ .release = dw9718_release,
+};
+
+static void dw9718_del(struct dw9718_info *info)
+{
+ dw9718_pm_exit(info);
+ if ((info->s_mode == NVC_SYNC_SLAVE) ||
+ (info->s_mode == NVC_SYNC_STEREO))
+ dw9718_pm_exit(info->s_info);
+
+ dw9718_sync_dis(info);
+ spin_lock(&dw9718_spinlock);
+ list_del_rcu(&info->list);
+ spin_unlock(&dw9718_spinlock);
+ synchronize_rcu();
+}
+
+static int dw9718_remove(struct i2c_client *client)
+{
+ struct dw9718_info *info = i2c_get_clientdata(client);
+ dev_dbg(&info->i2c_client->dev, "%s\n", __func__);
+ misc_deregister(&info->miscdev);
+ dw9718_del(info);
+ return 0;
+}
+
+static int nvc_debugfs_init(const char *dir_name,
+ struct dentry **d_entry, struct dentry **f_entry, void *info);
+
+static int dw9718_probe(
+ struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct dw9718_info *info;
+ char dname[16];
+
+ dev_dbg(&client->dev, "%s\n", __func__);
+ pr_info("dw9718: probing focuser.\n");
+
+ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL);
+ if (info == NULL) {
+ dev_err(&client->dev, "%s: kzalloc error\n", __func__);
+ return -ENOMEM;
+ }
+ info->i2c_client = client;
+ if (client->dev.platform_data) {
+ info->pdata = client->dev.platform_data;
+ } else {
+ info->pdata = &dw9718_default_pdata;
+ dev_dbg(&client->dev, "%s No platform data. Using defaults.\n",
+ __func__);
+ }
+
+ i2c_set_clientdata(client, info);
+ INIT_LIST_HEAD(&info->list);
+ spin_lock(&dw9718_spinlock);
+ list_add_rcu(&info->list, &dw9718_info_list);
+ spin_unlock(&dw9718_spinlock);
+ dw9718_power_get(info);
+ dw9718_sdata_init(info);
+
+ if (info->pdata->dev_name != 0)
+ strcpy(dname, info->pdata->dev_name);
+ else
+ strcpy(dname, "dw9718");
+
+ if (info->pdata->num)
+ snprintf(dname, sizeof(dname),
+ "%s.%u", dname, info->pdata->num);
+
+ info->miscdev.name = dname;
+ info->miscdev.fops = &dw9718_fileops;
+ info->miscdev.minor = MISC_DYNAMIC_MINOR;
+ if (misc_register(&info->miscdev)) {
+ dev_err(&client->dev, "%s unable to register misc device %s\n",
+ __func__, dname);
+ dw9718_del(info);
+ return -ENODEV;
+ }
+
+ nvc_debugfs_init(
+ info->miscdev.this_device->kobj.name, NULL, NULL, info);
+
+ return 0;
+}
+
+#ifdef ENABLE_DEBUGFS_INTERFACE
+static int nvc_status_show(struct seq_file *s, void *data)
+{
+ struct dw9718_info *k_info = s->private;
+ struct nv_focuser_config *pcfg = &k_info->nv_config;
+ struct nvc_focus_cap *pcap = &k_info->cap;
+
+ pr_info("%s\n", __func__);
+
+ seq_printf(s, "focuser status:\n"
+ " Limit = (%04d - %04d)\n"
+ " Range = (%04d - %04d)\n"
+ " Current Pos = %04d\n"
+ " Settle time = %04d\n"
+ " Macro = %04d\n"
+ " Infinity = %04d\n"
+ " Hyper = %04d\n"
+ " SlewRate = 0x%06x\n"
+ ,
+ pcfg->pos_actual_low, pcfg->pos_actual_high,
+ pcfg->pos_working_low, pcfg->pos_working_high,
+ k_info->cur_pos,
+ pcap->settle_time,
+ pcap->focus_macro,
+ pcap->focus_infinity,
+ pcap->focus_hyper,
+ pcfg->slew_rate
+ );
+
+ return 0;
+}
+
+static ssize_t nvc_attr_set(struct file *s,
+ const char __user *user_buf, size_t count, loff_t *ppos)
+{
+ struct dw9718_info *k_info =
+ ((struct seq_file *)s->private_data)->private;
+ struct nv_focuser_config *pcfg = &k_info->nv_config;
+ char buf[24];
+ int buf_size;
+ int err;
+ u32 val = 0;
+
+ pr_info("%s (%d)\n", __func__, count);
+
+ if (!user_buf || count <= 1)
+ return -EFAULT;
+
+ memset(buf, 0, sizeof(buf));
+ buf_size = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+
+ if (sscanf(buf + 1, "0x%x", &val) == 1)
+ goto set_attr;
+ if (sscanf(buf + 1, "0X%x", &val) == 1)
+ goto set_attr;
+ if (sscanf(buf + 1, "%d", &val) == 1)
+ goto set_attr;
+
+ pr_err("SYNTAX ERROR: %s\n", buf);
+ return -EFAULT;
+
+set_attr:
+ pr_info("new data = %x\n", val);
+ switch (buf[0]) {
+ case 'p':
+ pr_info("new pos = %d\n", val);
+ err = dw9718_position_wr(k_info, val);
+ if (err)
+ pr_err("ERROR set position %x\n", val);
+ break;
+ case 'h':
+ if (val <= pcfg->pos_working_low || val >= 1024) {
+ pr_info("new pos_high(%d) out of range\n",
+ val);
+ break;
+ }
+ pr_info("new pos_high = %d\n", val);
+ pcfg->pos_working_high = val;
+ break;
+ case 'l':
+ if (val >= pcfg->pos_working_high) {
+ pr_info("new pos_low(%d) out of range\n",
+ val);
+ break;
+ }
+ pr_info("new pos_low = %d\n", val);
+ pcfg->pos_working_low = val;
+ break;
+ case 'm':
+ pr_info("new vcm mode = %x\n", val);
+ pcfg->slew_rate = val;
+ dw9718_set_arc_mode(k_info);
+ break;
+ }
+
+ return count;
+}
+
+static int nvc_debugfs_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, nvc_status_show, inode->i_private);
+}
+
+static const struct file_operations nvc_debugfs_fops = {
+ .open = nvc_debugfs_open,
+ .read = seq_read,
+ .write = nvc_attr_set,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int nvc_debugfs_init(const char *dir_name,
+ struct dentry **d_entry, struct dentry **f_entry, void *info)
+{
+ struct dentry *dp, *fp;
+
+ dp = debugfs_create_dir(dir_name, NULL);
+ if (dp == NULL) {
+ pr_info("%s: debugfs create dir failed\n", __func__);
+ return -ENOMEM;
+ }
+
+ fp = debugfs_create_file("d", S_IRUGO|S_IWUSR,
+ dp, info, &nvc_debugfs_fops);
+ if (!fp) {
+ pr_info("%s: debugfs create file failed\n", __func__);
+ debugfs_remove_recursive(dp);
+ return -ENOMEM;
+ }
+
+ if (d_entry)
+ *d_entry = dp;
+ if (f_entry)
+ *f_entry = fp;
+ return 0;
+}
+#else
+static int nvc_debugfs_init(const char *dir_name,
+ struct dentry **d_entry, struct dentry **f_entry, void *info)
+{
+ return 0;
+}
+#endif
+
+
+static const struct i2c_device_id dw9718_id[] = {
+ { "dw9718", 0 },
+ { },
+};
+
+
+MODULE_DEVICE_TABLE(i2c, dw9718_id);
+
+static struct i2c_driver dw9718_i2c_driver = {
+ .driver = {
+ .name = "dw9718",
+ .owner = THIS_MODULE,
+ },
+ .id_table = dw9718_id,
+ .probe = dw9718_probe,
+ .remove = dw9718_remove,
+};
+
+static int __init dw9718_init(void)
+{
+ return i2c_add_driver(&dw9718_i2c_driver);
+}
+
+static void __exit dw9718_exit(void)
+{
+ i2c_del_driver(&dw9718_i2c_driver);
+}
+
+module_init(dw9718_init);
+module_exit(dw9718_exit);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/tegra/imx132.c b/drivers/media/video/tegra/imx132.c
index 22a1ab7023b4..6e89577047c9 100644
--- a/drivers/media/video/tegra/imx132.c
+++ b/drivers/media/video/tegra/imx132.c
@@ -1,15 +1,19 @@
/*
* imx132.c - imx132 sensor driver
*
- * Copyright (c) 2012-2013, NVIDIA Corporation. All Rights Reserved.
- *
- * Contributors:
- * Krupal Divvela <kdivvela@nvidia.com>
- *
- *
- * 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.
+ * Copyright (c) 2012 - 2013, NVIDIA CORPORATION. All rights reserved.
+
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
*/
#include <linux/delay.h>
@@ -756,6 +760,7 @@ imx132_remove(struct i2c_client *client)
static const struct i2c_device_id imx132_id[] = {
{ "imx132", 0 },
+ { }
};
MODULE_DEVICE_TABLE(i2c, imx132_id);
diff --git a/drivers/media/video/tegra/imx135.c b/drivers/media/video/tegra/imx135.c
new file mode 100644
index 000000000000..ca4d89417567
--- /dev/null
+++ b/drivers/media/video/tegra/imx135.c
@@ -0,0 +1,2417 @@
+/*
+ * imx135.c - imx135 sensor driver
+ *
+ * Copyright (c) 2013, NVIDIA CORPORATION, All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/i2c.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/regulator/consumer.h>
+#include <media/imx135.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+struct imx135_reg {
+ u16 addr;
+ u8 val;
+};
+
+struct imx135_info {
+ struct miscdevice miscdev_info;
+ int mode;
+ struct imx135_power_rail power;
+ struct imx135_sensordata sensor_data;
+ struct i2c_client *i2c_client;
+ struct imx135_platform_data *pdata;
+ struct mutex imx135_camera_lock;
+ struct dentry *debugdir;
+ atomic_t in_use;
+};
+
+#define IMX135_TABLE_WAIT_MS 0
+#define IMX135_TABLE_END 1
+#define IMX135_MAX_RETRIES 3
+#define IMX135_WAIT_MS 3
+
+#define IMX135_4208x3120_HDR
+
+#ifdef IMX135_4208x3120_HDR
+/* HDR */
+static struct imx135_reg mode_4208x3120[] = {
+ /* software reset */
+ {0x0103, 0x01},
+ /* global settings */
+ {0x0101, 0x00},
+ {0x0105, 0x01},
+ {0x0110, 0x00},
+ {0x0220, 0x01},
+ {0x3302, 0x11},
+ {0x3833, 0x20},
+ {0x3873, 0x03},
+ {0x3893, 0x00},
+ {0x3906, 0x08},
+ {0x3907, 0x01},
+ {0x391B, 0x00},
+ {0x3C09, 0x01},
+ {0x600A, 0x00},
+ {0x3008, 0xB0},
+ {0x320A, 0x01},
+ {0x320D, 0x10},
+ {0x3216, 0x2E},
+ {0x322C, 0x02},
+ {0x3409, 0x0C},
+ {0x340C, 0x2D},
+ {0x3411, 0x39},
+ {0x3414, 0x1E},
+ {0x3427, 0x04},
+ {0x3480, 0x1E},
+ {0x3484, 0x1E},
+ {0x3488, 0x1E},
+ {0x348C, 0x1E},
+ {0x3490, 0x1E},
+ {0x3494, 0x1E},
+ {0x3511, 0x8F},
+ {0x364F, 0x2D},
+
+ /* Clock Setting */
+ {0x011E, 0x18},
+ {0x011F, 0x00},
+ {0x0301, 0x05},
+ {0x0303, 0x01},
+ {0x0305, 0x0C},
+ {0x0309, 0x05},
+ {0x030B, 0x01},
+ {0x030C, 0x01},
+ {0x030D, 0xC2},
+ {0x030E, 0x01},
+ {0x3A06, 0x11},
+
+ /* Mode Settings */
+ {0x0108, 0x03},
+ {0x0112, 0x0E},
+ {0x0113, 0x0A},
+ {0x0381, 0x01},
+ {0x0383, 0x01},
+ {0x0385, 0x01},
+ {0x0387, 0x01},
+ {0x0390, 0x00},
+ {0x0391, 0x11},
+ {0x0392, 0x00},
+ {0x0401, 0x00},
+ {0x0404, 0x00},
+ {0x0405, 0x10},
+ {0x4082, 0x01},
+ {0x4083, 0x01},
+ {0x7006, 0x04},
+
+ /* Optinal/Function settings */
+ {0x0700, 0x00},
+ {0x3A63, 0x00},
+ {0x4100, 0xF8},
+ {0x4203, 0xFF},
+ {0x4344, 0x00},
+ {0x441C, 0x01},
+
+ /* Size Setting */
+ {0x0340, 0x0C},
+ {0x0341, 0xD0},
+ {0x0342, 0x11},
+ {0x0343, 0xDC},
+ {0x0344, 0x00},
+ {0x0345, 0x00},
+ {0x0346, 0x00},
+ {0x0347, 0x00},
+ {0x0348, 0x10},
+ {0x0349, 0x6F},
+ {0x034A, 0x0C},
+ {0x034B, 0x2F},
+ {0x034C, 0x10},
+ {0x034D, 0x70},
+ {0x034E, 0x0C},
+ {0x034F, 0x30},
+ {0x0350, 0x00},
+ {0x0351, 0x00},
+ {0x0352, 0x00},
+ {0x0353, 0x00},
+ {0x0354, 0x10},
+ {0x0355, 0x70},
+ {0x0356, 0x0C},
+ {0x0357, 0x30},
+ {0x301D, 0x30},
+ {0x3310, 0x10},
+ {0x3311, 0x70},
+ {0x3312, 0x0C},
+ {0x3313, 0x30},
+ {0x331C, 0x01},
+ {0x331D, 0x68},
+ {0x4084, 0x00},
+ {0x4085, 0x00},
+ {0x4086, 0x00},
+ {0x4087, 0x00},
+ {0x4400, 0x00},
+
+ /* Global Timing Setting */
+ {0x0830, 0x87},
+ {0x0831, 0x3F},
+ {0x0832, 0x67},
+ {0x0833, 0x3F},
+ {0x0834, 0x3F},
+ {0x0835, 0x4F},
+ {0x0836, 0xDF},
+ {0x0837, 0x47},
+ {0x0839, 0x1F},
+ {0x083A, 0x17},
+ {0x083B, 0x02},
+
+ /* Integration Time Setting */
+ {0x0202, 0x0C},
+ {0x0203, 0xCC},
+
+ /* Gain Setting */
+ {0x0205, 0x00},
+ {0x020E, 0x01},
+ {0x020F, 0x00},
+ {0x0210, 0x01},
+ {0x0211, 0x00},
+ {0x0212, 0x01},
+ {0x0213, 0x00},
+ {0x0214, 0x01},
+ {0x0215, 0x00},
+
+ /* HDR Setting */
+ {0x0230, 0x00},
+ {0x0231, 0x00},
+ {0x0233, 0x00},
+ {0x0234, 0x00},
+ {0x0235, 0x40},
+ {0x0238, 0x01},
+ {0x0239, 0x04},
+ {0x023B, 0x00},
+ {0x023C, 0x01},
+ {0x33B0, 0x10},
+ {0x33B1, 0x70},
+ {0x33B3, 0x01},
+ {0x33B4, 0x01},
+ {0x3800, 0x00},
+
+ {0x3A43, 0x01},
+ /* stream on */
+ {0x0100, 0x01},
+
+ {IMX135_TABLE_WAIT_MS, IMX135_WAIT_MS},
+ {IMX135_TABLE_END, 0x00}
+};
+#else
+/* standard */
+static struct imx135_reg mode_4208x3120[] = {
+ /* software reset */
+ {0x0103, 0x01},
+ /* global settings */
+ {0x0101, 0x00},
+ {0x0105, 0x01},
+ {0x0110, 0x00},
+ {0x0220, 0x01},
+ {0x3302, 0x11},
+ {0x3833, 0x20},
+ {0x3893, 0x00},
+ {0x3906, 0x08},
+ {0x3907, 0x01},
+ {0x391B, 0x01},
+ {0x3C09, 0x01},
+ {0x600A, 0x00},
+ {0x3008, 0xB0},
+ {0x320A, 0x01},
+ {0x320D, 0x10},
+ {0x3216, 0x2E},
+ {0x322C, 0x02},
+ {0x3409, 0x0C},
+ {0x340C, 0x2D},
+ {0x3411, 0x39},
+ {0x3414, 0x1E},
+ {0x3427, 0x04},
+ {0x3480, 0x1E},
+ {0x3484, 0x1E},
+ {0x3488, 0x1E},
+ {0x348C, 0x1E},
+ {0x3490, 0x1E},
+ {0x3494, 0x1E},
+ {0x3511, 0x8F},
+ {0x364F, 0x2D},
+
+ /* Clock Setting */
+ {0x011E, 0x18},
+ {0x011F, 0x00},
+ {0x0301, 0x05},
+ {0x0303, 0x01},
+ {0x0305, 0x0C},
+ {0x0309, 0x05},
+ {0x030B, 0x01},
+ {0x030C, 0x01},
+ {0x030D, 0xC2},
+ {0x030E, 0x01},
+ {0x3A06, 0x11},
+
+ /* Mode Settings */
+ {0x0108, 0x03},
+ {0x0112, 0x0A},
+ {0x0113, 0x0A},
+ {0x0381, 0x01},
+ {0x0383, 0x01},
+ {0x0385, 0x01},
+ {0x0387, 0x01},
+ {0x0390, 0x00},
+ {0x0391, 0x11},
+ {0x0392, 0x00},
+ {0x0401, 0x00},
+ {0x0404, 0x00},
+ {0x0405, 0x10},
+ {0x4082, 0x01},
+ {0x4083, 0x01},
+ {0x7006, 0x04},
+
+ /* Optinal/Function settings */
+ {0x0700, 0x00},
+ {0x3A63, 0x00},
+ {0x4100, 0xF8},
+ {0x4203, 0xFF},
+ {0x4344, 0x00},
+ {0x441C, 0x01},
+
+ /* Size Setting */
+ {0x0340, 0x0C},
+ {0x0341, 0xD0},
+ {0x0342, 0x11},
+ {0x0343, 0xDC},
+ {0x0344, 0x00},
+ {0x0345, 0x00},
+ {0x0346, 0x00},
+ {0x0347, 0x00},
+ {0x0348, 0x10},
+ {0x0349, 0x6F},
+ {0x034A, 0x0C},
+ {0x034B, 0x2F},
+ {0x034C, 0x10},
+ {0x034D, 0x70},
+ {0x034E, 0x0C},
+ {0x034F, 0x30},
+ {0x0350, 0x00},
+ {0x0351, 0x00},
+ {0x0352, 0x00},
+ {0x0353, 0x00},
+ {0x0354, 0x10},
+ {0x0355, 0x70},
+ {0x0356, 0x0C},
+ {0x0357, 0x30},
+ {0x301D, 0x30},
+ {0x3310, 0x10},
+ {0x3311, 0x70},
+ {0x3312, 0x0C},
+ {0x3313, 0x30},
+ {0x331C, 0x01},
+ {0x331D, 0x68},
+ {0x4084, 0x00},
+ {0x4085, 0x00},
+ {0x4086, 0x00},
+ {0x4087, 0x00},
+ {0x4400, 0x00},
+
+ /* Global Timing Setting */
+ {0x0830, 0x87},
+ {0x0831, 0x3F},
+ {0x0832, 0x67},
+ {0x0833, 0x3F},
+ {0x0834, 0x3F},
+ {0x0835, 0x4F},
+ {0x0836, 0xDF},
+ {0x0837, 0x47},
+ {0x0839, 0x1F},
+ {0x083A, 0x17},
+ {0x083B, 0x02},
+
+ /* Integration Time Setting */
+ {0x0202, 0x0C},
+ {0x0203, 0xCC},
+
+ /* Gain Setting */
+ {0x0205, 0x04},
+ {0x020E, 0x01},
+ {0x020F, 0x00},
+ {0x0210, 0x01},
+ {0x0211, 0x00},
+ {0x0212, 0x01},
+ {0x0213, 0x00},
+ {0x0214, 0x01},
+ {0x0215, 0x00},
+
+ /* HDR Setting */
+ {0x0230, 0x00},
+ {0x0231, 0x00},
+ {0x0233, 0x00},
+ {0x0234, 0x00},
+ {0x0235, 0x40},
+ {0x0238, 0x01},
+ {0x0239, 0x04},
+ {0x023B, 0x00},
+ {0x023C, 0x01},
+ {0x33B0, 0x04},
+ {0x33B1, 0x00},
+ {0x33B3, 0x00},
+ {0x33B4, 0x01},
+ {0x3800, 0x00},
+
+ {0x3A43, 0x01},
+ /* stream on */
+ {0x0100, 0x01},
+
+ {IMX135_TABLE_WAIT_MS, IMX135_WAIT_MS},
+ {IMX135_TABLE_END, 0x00}
+};
+#endif
+
+static struct imx135_reg mode_1920x1080[] = {
+ /* software reset */
+ {0x0103, 0x01},
+ /* global settings */
+ {0x0101, 0x00},
+ {0x0105, 0x01},
+ {0x0110, 0x00},
+ {0x0220, 0x01},
+ {0x3302, 0x11},
+ {0x3833, 0x20},
+ {0x3893, 0x00},
+ {0x3906, 0x08},
+ {0x3907, 0x01},
+ {0x391B, 0x01},
+ {0x3C09, 0x01},
+ {0x600A, 0x00},
+ {0x3008, 0xB0},
+ {0x320A, 0x01},
+ {0x320D, 0x10},
+ {0x3216, 0x2E},
+ {0x322C, 0x02},
+ {0x3409, 0x0C},
+ {0x340C, 0x2D},
+ {0x3411, 0x39},
+ {0x3414, 0x1E},
+ {0x3427, 0x04},
+ {0x3480, 0x1E},
+ {0x3484, 0x1E},
+ {0x3488, 0x1E},
+ {0x348C, 0x1E},
+ {0x3490, 0x1E},
+ {0x3494, 0x1E},
+ {0x3511, 0x8F},
+ {0x364F, 0x2D},
+
+ /* Clock Setting */
+ {0x011E, 0x18},
+ {0x011F, 0x00},
+ {0x0301, 0x05},
+ {0x0303, 0x01},
+ {0x0305, 0x0C},
+ {0x0309, 0x05},
+ {0x030B, 0x02},
+ {0x030C, 0x01},
+ {0x030D, 0xC2},
+ {0x030E, 0x01},
+ {0x3A06, 0x12},
+
+ /* Mode Settings */
+ {0x0108, 0x03},
+ {0x0112, 0x0A},
+ {0x0113, 0x0A},
+ {0x0381, 0x01},
+ {0x0383, 0x01},
+ {0x0385, 0x01},
+ {0x0387, 0x01},
+ {0x0390, 0x01},
+ {0x0391, 0x22},
+ {0x0392, 0x00},
+ {0x0401, 0x02},
+ {0x0404, 0x00},
+ {0x0405, 0x11},
+ {0x4082, 0x00},
+ {0x4083, 0x00},
+ {0x7006, 0x04},
+
+ /* Optinal/Function settings */
+ {0x0700, 0x00},
+ {0x3A63, 0x00},
+ {0x4100, 0xF8},
+ {0x4203, 0xFF},
+ {0x4344, 0x00},
+ {0x441C, 0x01},
+
+ /* Size Setting */
+ {0x0340, 0x0A},
+ {0x0341, 0x40},
+ {0x0342, 0x11},
+ {0x0343, 0xDC},
+ {0x0344, 0x00},
+ {0x0345, 0x40},
+ {0x0346, 0x01},
+ {0x0347, 0x9C},
+ {0x0348, 0x10},
+ {0x0349, 0x2F},
+ {0x034A, 0x0A},
+ {0x034B, 0x93},
+ {0x034C, 0x07},
+ {0x034D, 0x80},
+ {0x034E, 0x04},
+ {0x034F, 0x38},
+ {0x0350, 0x00},
+ {0x0351, 0x00},
+ {0x0352, 0x00},
+ {0x0353, 0x00},
+ {0x0354, 0x07},
+ {0x0355, 0xF8},
+ {0x0356, 0x04},
+ {0x0357, 0x7C},
+ {0x301D, 0x30},
+ {0x3310, 0x07},
+ {0x3311, 0x80},
+ {0x3312, 0x04},
+ {0x3313, 0x38},
+ {0x331C, 0x00},
+ {0x331D, 0xD2},
+ {0x4084, 0x07},
+ {0x4085, 0x80},
+ {0x4086, 0x04},
+ {0x4087, 0x38},
+ {0x4400, 0x00},
+
+ /* Global Timing Setting */
+ {0x0830, 0x67},
+ {0x0831, 0x27},
+ {0x0832, 0x47},
+ {0x0833, 0x27},
+ {0x0834, 0x27},
+ {0x0835, 0x1F},
+ {0x0836, 0x87},
+ {0x0837, 0x2F},
+ {0x0839, 0x1F},
+ {0x083A, 0x17},
+ {0x083B, 0x02},
+
+ /* Integration Time Setting */
+ {0x0202, 0x0A},
+ {0x0203, 0x3C},
+
+ /* Gain Setting */
+ {0x0205, 0x00},
+ {0x020E, 0x01},
+ {0x020F, 0x00},
+ {0x0210, 0x01},
+ {0x0211, 0x00},
+ {0x0212, 0x01},
+ {0x0213, 0x00},
+ {0x0214, 0x01},
+ {0x0215, 0x00},
+
+ /* HDR Setting */
+ {0x0230, 0x00},
+ {0x0231, 0x00},
+ {0x0233, 0x00},
+ {0x0234, 0x00},
+ {0x0235, 0x40},
+ {0x0238, 0x01},
+ {0x0239, 0x04},
+ {0x023B, 0x00},
+ {0x023C, 0x01},
+ {0x33B0, 0x04},
+ {0x33B1, 0x00},
+ {0x33B3, 0x00},
+ {0x33B4, 0x01},
+ {0x3800, 0x00},
+
+ {0x3A43, 0x01},
+ /* stream on */
+ {0x0100, 0x01},
+
+ {IMX135_TABLE_WAIT_MS, IMX135_WAIT_MS},
+ {IMX135_TABLE_END, 0x00}
+};
+
+#ifdef IMX135_1280x720_90_FPS
+/* 720p 90fps */
+static struct imx135_reg mode_1280x720[] = {
+ /* software reset */
+ {0x0103, 0x01},
+ /* global settings */
+ {0x0101, 0x00},
+ {0x0105, 0x01},
+ {0x0110, 0x00},
+ {0x0220, 0x01},
+ {0x3302, 0x11},
+ {0x3833, 0x20},
+ {0x3893, 0x00},
+ {0x3906, 0x08},
+ {0x3907, 0x01},
+ {0x391B, 0x01},
+ {0x3C09, 0x01},
+ {0x600A, 0x00},
+ {0x3008, 0xB0},
+ {0x320A, 0x01},
+ {0x320D, 0x10},
+ {0x3216, 0x2E},
+ {0x322C, 0x02},
+ {0x3409, 0x0C},
+ {0x340C, 0x2D},
+ {0x3411, 0x39},
+ {0x3414, 0x1E},
+ {0x3427, 0x04},
+ {0x3480, 0x1E},
+ {0x3484, 0x1E},
+ {0x3488, 0x1E},
+ {0x348C, 0x1E},
+ {0x3490, 0x1E},
+ {0x3494, 0x1E},
+ {0x3511, 0x8F},
+ {0x364F, 0x2D},
+
+ /* Clock Setting */
+ {0x011E, 0x18},
+ {0x011F, 0x00},
+ {0x0301, 0x05},
+ {0x0303, 0x01},
+ {0x0305, 0x0C},
+ {0x0309, 0x05},
+ {0x030B, 0x02},
+ {0x030C, 0x01},
+ {0x030D, 0xC2},
+ {0x030E, 0x01},
+ {0x3A06, 0x12},
+
+ /* Mode Settings */
+ {0x0108, 0x03},
+ {0x0112, 0x0A},
+ {0x0113, 0x0A},
+ {0x0381, 0x01},
+ {0x0383, 0x01},
+ {0x0385, 0x01},
+ {0x0387, 0x01},
+ {0x0390, 0x01},
+ {0x0391, 0x22},
+ {0x0392, 0x00},
+ {0x0401, 0x00},
+ {0x0404, 0x00},
+ {0x0405, 0x10},
+ {0x4082, 0x01},
+ {0x4083, 0x01},
+ {0x7006, 0x04},
+
+ /* Optinal/Function settings */
+ {0x0700, 0x00},
+ {0x3A63, 0x00},
+ {0x4100, 0xF8},
+ {0x4203, 0xFF},
+ {0x4344, 0x00},
+ {0x441C, 0x01},
+
+ /* Size Setting */
+ {0x0340, 0x03},
+ {0x0341, 0x6A},
+ {0x0342, 0x11},
+ {0x0343, 0xDC},
+ {0x0344, 0x03},
+ {0x0345, 0x38},
+ {0x0346, 0x03},
+ {0x0347, 0x48},
+ {0x0348, 0x0D},
+ {0x0349, 0x37},
+ {0x034A, 0x08},
+ {0x034B, 0xE7},
+ {0x034C, 0x05},
+ {0x034D, 0x00},
+ {0x034E, 0x02},
+ {0x034F, 0xD0},
+ {0x0350, 0x00},
+ {0x0351, 0x00},
+ {0x0352, 0x00},
+ {0x0353, 0x00},
+ {0x0354, 0x05},
+ {0x0355, 0x00},
+ {0x0356, 0x02},
+ {0x0357, 0xD0},
+ {0x301D, 0x30},
+ {0x3310, 0x05},
+ {0x3311, 0x00},
+ {0x3312, 0x02},
+ {0x3313, 0xD0},
+ {0x331C, 0x00},
+ {0x331D, 0x10},
+ {0x4084, 0x00},
+ {0x4085, 0x00},
+ {0x4086, 0x00},
+ {0x4087, 0x00},
+ {0x4400, 0x00},
+
+ /* Global Timing Setting */
+ {0x0830, 0x67},
+ {0x0831, 0x27},
+ {0x0832, 0x47},
+ {0x0833, 0x27},
+ {0x0834, 0x27},
+ {0x0835, 0x1F},
+ {0x0836, 0x87},
+ {0x0837, 0x2F},
+ {0x0839, 0x1F},
+ {0x083A, 0x17},
+ {0x083B, 0x02},
+
+ /* Integration Time Setting */
+ {0x0202, 0x03},
+ {0x0203, 0x66},
+
+ /* Gain Setting */
+ {0x0205, 0x00},
+ {0x020E, 0x01},
+ {0x020F, 0x00},
+ {0x0210, 0x01},
+ {0x0211, 0x00},
+ {0x0212, 0x01},
+ {0x0213, 0x00},
+ {0x0214, 0x01},
+ {0x0215, 0x00},
+
+ /* HDR Setting */
+ {0x0230, 0x00},
+ {0x0231, 0x00},
+ {0x0233, 0x00},
+ {0x0234, 0x00},
+ {0x0235, 0x40},
+ {0x0238, 0x01},
+ {0x0239, 0x04},
+ {0x023B, 0x00},
+ {0x023C, 0x01},
+ {0x33B0, 0x04},
+ {0x33B1, 0x00},
+ {0x33B3, 0x00},
+ {0x33B4, 0x01},
+ {0x3800, 0x00},
+
+ {0x3A43, 0x01},
+ /* stream on */
+ {0x0100, 0x01},
+
+ {IMX135_TABLE_WAIT_MS, IMX135_WAIT_MS},
+ {IMX135_TABLE_END, 0x00}
+};
+#else
+/* 720p 30fps */
+static struct imx135_reg mode_1280x720[] = {
+ /* software reset */
+ {0x0103, 0x01},
+ /* global settings */
+ {0x0101, 0x00},
+ {0x0105, 0x01},
+ {0x0110, 0x00},
+ {0x0220, 0x01},
+ {0x3302, 0x11},
+ {0x3833, 0x20},
+ {0x3893, 0x00},
+ {0x3906, 0x08},
+ {0x3907, 0x01},
+ {0x391B, 0x01},
+ {0x3C09, 0x01},
+ {0x600A, 0x00},
+ {0x3008, 0xB0},
+ {0x320A, 0x01},
+ {0x320D, 0x10},
+ {0x3216, 0x2E},
+ {0x322C, 0x02},
+ {0x3409, 0x0C},
+ {0x340C, 0x2D},
+ {0x3411, 0x39},
+ {0x3414, 0x1E},
+ {0x3427, 0x04},
+ {0x3480, 0x1E},
+ {0x3484, 0x1E},
+ {0x3488, 0x1E},
+ {0x348C, 0x1E},
+ {0x3490, 0x1E},
+ {0x3494, 0x1E},
+ {0x3511, 0x8F},
+ {0x364F, 0x2D},
+
+ /* Clock Setting */
+ {0x011E, 0x18},
+ {0x011F, 0x00},
+ {0x0301, 0x05},
+ {0x0303, 0x01},
+ {0x0305, 0x0C},
+ {0x0309, 0x05},
+ {0x030B, 0x02},
+ {0x030C, 0x01},
+ {0x030D, 0xC2},
+ {0x030E, 0x01},
+ {0x3A06, 0x12},
+
+ /* Mode Settings */
+ {0x0108, 0x03},
+ {0x0112, 0x0A},
+ {0x0113, 0x0A},
+ {0x0381, 0x01},
+ {0x0383, 0x01},
+ {0x0385, 0x01},
+ {0x0387, 0x01},
+ {0x0390, 0x01},
+ {0x0391, 0x22},
+ {0x0392, 0x00},
+ {0x0401, 0x02},
+ {0x0404, 0x00},
+ {0x0405, 0x1A},
+ {0x4082, 0x00},
+ {0x4083, 0x00},
+ {0x7006, 0x04},
+
+ /* Optinal/Function settings */
+ {0x0700, 0x00},
+ {0x3A63, 0x00},
+ {0x4100, 0xF8},
+ {0x4203, 0xFF},
+ {0x4344, 0x00},
+ {0x441C, 0x01},
+
+ /* Size Setting */
+ {0x0340, 0x0A},
+ {0x0341, 0x40},
+ {0x0342, 0x11},
+ {0x0343, 0xDC},
+ {0x0344, 0x00},
+ {0x0345, 0x18},
+ {0x0346, 0x01},
+ {0x0347, 0x88},
+ {0x0348, 0x10},
+ {0x0349, 0x57},
+ {0x034A, 0x0A},
+ {0x034B, 0xAB},
+ {0x034C, 0x05},
+ {0x034D, 0x00},
+ {0x034E, 0x02},
+ {0x034F, 0xD0},
+ {0x0350, 0x00},
+ {0x0351, 0x00},
+ {0x0352, 0x00},
+ {0x0353, 0x00},
+ {0x0354, 0x08},
+ {0x0355, 0x20},
+ {0x0356, 0x04},
+ {0x0357, 0x92},
+ {0x301D, 0x30},
+ {0x3310, 0x05},
+ {0x3311, 0x00},
+ {0x3312, 0x02},
+ {0x3313, 0xD0},
+ {0x331C, 0x02},
+ {0x331D, 0x18},
+ {0x4084, 0x05},
+ {0x4085, 0x00},
+ {0x4086, 0x02},
+ {0x4087, 0xD0},
+ {0x4400, 0x00},
+
+ /* Global Timing Setting */
+ {0x0830, 0x67},
+ {0x0831, 0x27},
+ {0x0832, 0x47},
+ {0x0833, 0x27},
+ {0x0834, 0x27},
+ {0x0835, 0x1F},
+ {0x0836, 0x87},
+ {0x0837, 0x2F},
+ {0x0839, 0x1F},
+ {0x083A, 0x17},
+ {0x083B, 0x02},
+
+ /* Integration Time Setting */
+ {0x0202, 0x0A},
+ {0x0203, 0x3C},
+
+ /* Gain Setting */
+ {0x0205, 0x00},
+ {0x020E, 0x01},
+ {0x020F, 0x00},
+ {0x0210, 0x01},
+ {0x0211, 0x00},
+ {0x0212, 0x01},
+ {0x0213, 0x00},
+ {0x0214, 0x01},
+ {0x0215, 0x00},
+
+ /* HDR Setting */
+ {0x0230, 0x00},
+ {0x0231, 0x00},
+ {0x0233, 0x00},
+ {0x0234, 0x00},
+ {0x0235, 0x40},
+ {0x0238, 0x01},
+ {0x0239, 0x04},
+ {0x023B, 0x00},
+ {0x023C, 0x01},
+ {0x33B0, 0x04},
+ {0x33B1, 0x00},
+ {0x33B3, 0x00},
+ {0x33B4, 0x01},
+ {0x3800, 0x00},
+
+ {0x3A43, 0x01},
+ /* stream on */
+ {0x0100, 0x01},
+
+ {IMX135_TABLE_WAIT_MS, IMX135_WAIT_MS},
+ {IMX135_TABLE_END, 0x00}
+};
+#endif
+
+static struct imx135_reg mode_2616x1472[] = {
+ /* software reset */
+ {0x0103, 0x01},
+ /* global settings */
+ {0x0101, 0x00},
+ {0x0105, 0x01},
+ {0x0110, 0x00},
+ {0x0220, 0x01},
+ {0x3302, 0x11},
+ {0x3833, 0x20},
+ {0x3873, 0x03},
+ {0x3893, 0x00},
+ {0x3906, 0x08},
+ {0x3907, 0x01},
+ {0x391B, 0x00},
+ {0x3C09, 0x01},
+ {0x600A, 0x00},
+ {0x3008, 0xB0},
+ {0x320A, 0x01},
+ {0x320D, 0x10},
+ {0x3216, 0x2E},
+ {0x322C, 0x02},
+ {0x3409, 0x0C},
+ {0x340C, 0x2D},
+ {0x3411, 0x39},
+ {0x3414, 0x1E},
+ {0x3427, 0x04},
+ {0x3480, 0x1E},
+ {0x3484, 0x1E},
+ {0x3488, 0x1E},
+ {0x348C, 0x1E},
+ {0x3490, 0x1E},
+ {0x3494, 0x1E},
+ {0x3511, 0x8F},
+ {0x364F, 0x2D},
+
+ /* Clock Setting */
+ {0x011E, 0x18},
+ {0x011F, 0x00},
+ {0x0301, 0x05},
+ {0x0303, 0x01},
+ {0x0305, 0x0C},
+ {0x0309, 0x05},
+ {0x030B, 0x01},
+ {0x030C, 0x01},
+ {0x030D, 0xC2},
+ {0x030E, 0x01},
+ {0x3A06, 0x11},
+
+ /* Mode Settings */
+ {0x0108, 0x03},
+ {0x0112, 0x0E},
+ {0x0113, 0x0A},
+ {0x0381, 0x01},
+ {0x0383, 0x01},
+ {0x0385, 0x01},
+ {0x0387, 0x01},
+ {0x0390, 0x00},
+ {0x0391, 0x11},
+ {0x0392, 0x00},
+ {0x0401, 0x00},
+ {0x0404, 0x00},
+ {0x0405, 0x10},
+ {0x4082, 0x01},
+ {0x4083, 0x01},
+ {0x7006, 0x04},
+
+ /* Optinal/Function settings */
+ {0x0700, 0x00},
+ {0x3A63, 0x00},
+ {0x4100, 0xF8},
+ {0x4203, 0xFF},
+ {0x4344, 0x00},
+ {0x441C, 0x01},
+
+ /* Size Setting */
+ {0x0340, 0x0A},
+ {0x0341, 0x40},
+ {0x0342, 0x11},
+ {0x0343, 0xDC},
+ {0x0344, 0x03},
+ {0x0345, 0x1C},
+ {0x0346, 0x03},
+ {0x0347, 0x38},
+ {0x0348, 0x0D},
+ {0x0349, 0x53},
+ {0x034A, 0x08},
+ {0x034B, 0xF7},
+ {0x034C, 0x0A},
+ {0x034D, 0x38},
+ {0x034E, 0x05},
+ {0x034F, 0xC0},
+ {0x0350, 0x00},
+ {0x0351, 0x00},
+ {0x0352, 0x00},
+ {0x0353, 0x00},
+ {0x0354, 0x0A},
+ {0x0355, 0x38},
+ {0x0356, 0x05},
+ {0x0357, 0xC0},
+ {0x301D, 0x30},
+ {0x3310, 0x0A},
+ {0x3311, 0x38},
+ {0x3312, 0x05},
+ {0x3313, 0xC0},
+ {0x331C, 0x08},
+ {0x331D, 0xD4},
+ {0x4084, 0x00},
+ {0x4085, 0x00},
+ {0x4086, 0x00},
+ {0x4087, 0x00},
+ {0x4400, 0x00},
+
+ /* Global Timing Setting */
+ {0x0830, 0x87},
+ {0x0831, 0x3F},
+ {0x0832, 0x67},
+ {0x0833, 0x3F},
+ {0x0834, 0x3F},
+ {0x0835, 0x4F},
+ {0x0836, 0xDF},
+ {0x0837, 0x47},
+ {0x0839, 0x1F},
+ {0x083A, 0x17},
+ {0x083B, 0x02},
+
+ /* Integration Time Setting */
+ {0x0202, 0x0A},
+ {0x0203, 0x3C},
+
+ /* Gain Setting */
+ {0x0205, 0x00},
+ {0x020E, 0x01},
+ {0x020F, 0x00},
+ {0x0210, 0x01},
+ {0x0211, 0x00},
+ {0x0212, 0x01},
+ {0x0213, 0x00},
+ {0x0214, 0x01},
+ {0x0215, 0x00},
+
+ /* HDR Setting */
+ {0x0230, 0x00},
+ {0x0231, 0x00},
+ {0x0233, 0x00},
+ {0x0234, 0x00},
+ {0x0235, 0x40},
+ {0x0238, 0x01},
+ {0x0239, 0x04},
+ {0x023B, 0x00},
+ {0x023C, 0x01},
+ {0x33B0, 0x0A},
+ {0x33B1, 0x38},
+ {0x33B3, 0x01},
+ {0x33B4, 0x01},
+ {0x3800, 0x00},
+
+ {0x3A43, 0x01},
+ /* stream on */
+ {0x0100, 0x01},
+
+ {IMX135_TABLE_WAIT_MS, IMX135_WAIT_MS},
+ {IMX135_TABLE_END, 0x00}
+};
+
+static struct imx135_reg mode_3896x2192[] = {
+ /* software reset */
+ {0x0103, 0x01},
+ /* global settings */
+ {0x0101, 0x00},
+ {0x0105, 0x01},
+ {0x0110, 0x00},
+ {0x0220, 0x01},
+ {0x3302, 0x11},
+ {0x3833, 0x20},
+ {0x3873, 0x03},
+ {0x3893, 0x00},
+ {0x3906, 0x08},
+ {0x3907, 0x01},
+ {0x391B, 0x00},
+ {0x3C09, 0x01},
+ {0x600A, 0x00},
+ {0x3008, 0xB0},
+ {0x320A, 0x01},
+ {0x320D, 0x10},
+ {0x3216, 0x2E},
+ {0x322C, 0x02},
+ {0x3409, 0x0C},
+ {0x340C, 0x2D},
+ {0x3411, 0x39},
+ {0x3414, 0x1E},
+ {0x3427, 0x04},
+ {0x3480, 0x1E},
+ {0x3484, 0x1E},
+ {0x3488, 0x1E},
+ {0x348C, 0x1E},
+ {0x3490, 0x1E},
+ {0x3494, 0x1E},
+ {0x3511, 0x8F},
+ {0x364F, 0x2D},
+
+ /* Clock Setting */
+ {0x011E, 0x18},
+ {0x011F, 0x00},
+ {0x0301, 0x05},
+ {0x0303, 0x01},
+ {0x0305, 0x0C},
+ {0x0309, 0x05},
+ {0x030B, 0x01},
+ {0x030C, 0x01},
+ {0x030D, 0xC2},
+ {0x030E, 0x01},
+ {0x3A06, 0x11},
+
+ /* Mode Settings */
+ {0x0108, 0x03},
+ {0x0112, 0x0E},
+ {0x0113, 0x0A},
+ {0x0381, 0x01},
+ {0x0383, 0x01},
+ {0x0385, 0x01},
+ {0x0387, 0x01},
+ {0x0390, 0x00},
+ {0x0391, 0x11},
+ {0x0392, 0x00},
+ {0x0401, 0x00},
+ {0x0404, 0x00},
+ {0x0405, 0x10},
+ {0x4082, 0x01},
+ {0x4083, 0x01},
+ {0x7006, 0x04},
+
+ /* Optinal/Function settings */
+ {0x0700, 0x00},
+ {0x3A63, 0x00},
+ {0x4100, 0xF8},
+ {0x4203, 0xFF},
+ {0x4344, 0x00},
+ {0x441C, 0x01},
+
+ /* Size Setting */
+ {0x0340, 0x0A},
+ {0x0341, 0x40},
+ {0x0342, 0x11},
+ {0x0343, 0xDC},
+ {0x0344, 0x00},
+ {0x0345, 0x9C},
+ {0x0346, 0x01},
+ {0x0347, 0xD0},
+ {0x0348, 0x0F},
+ {0x0349, 0xD3},
+ {0x034A, 0x0A},
+ {0x034B, 0x5F},
+ {0x034C, 0x0F},
+ {0x034D, 0x38},
+ {0x034E, 0x08},
+ {0x034F, 0x90},
+ {0x0350, 0x00},
+ {0x0351, 0x00},
+ {0x0352, 0x00},
+ {0x0353, 0x00},
+ {0x0354, 0x0F},
+ {0x0355, 0x38},
+ {0x0356, 0x08},
+ {0x0357, 0x90},
+ {0x301D, 0x30},
+ {0x3310, 0x0F},
+ {0x3311, 0x38},
+ {0x3312, 0x08},
+ {0x3313, 0x90},
+ {0x331C, 0x0F},
+ {0x331D, 0x32},
+ {0x4084, 0x00},
+ {0x4085, 0x00},
+ {0x4086, 0x00},
+ {0x4087, 0x00},
+ {0x4400, 0x00},
+
+ /* Global Timing Setting */
+ {0x0830, 0x87},
+ {0x0831, 0x3F},
+ {0x0832, 0x67},
+ {0x0833, 0x3F},
+ {0x0834, 0x3F},
+ {0x0835, 0x4F},
+ {0x0836, 0xDF},
+ {0x0837, 0x47},
+ {0x0839, 0x1F},
+ {0x083A, 0x17},
+ {0x083B, 0x02},
+
+ /* Integration Time Setting */
+ {0x0202, 0x0A},
+ {0x0203, 0x3C},
+
+ /* Gain Setting */
+ {0x0205, 0x00},
+ {0x020E, 0x01},
+ {0x020F, 0x00},
+ {0x0210, 0x01},
+ {0x0211, 0x00},
+ {0x0212, 0x01},
+ {0x0213, 0x00},
+ {0x0214, 0x01},
+ {0x0215, 0x00},
+
+ /* HDR Setting */
+ {0x0230, 0x00},
+ {0x0231, 0x00},
+ {0x0233, 0x00},
+ {0x0234, 0x00},
+ {0x0235, 0x40},
+ {0x0238, 0x01},
+ {0x0239, 0x04},
+ {0x023B, 0x00},
+ {0x023C, 0x01},
+ {0x33B0, 0x0F},
+ {0x33B1, 0x38},
+ {0x33B3, 0x01},
+ {0x33B4, 0x01},
+ {0x3800, 0x00},
+
+ {0x3A43, 0x01},
+ /* stream on */
+ {0x0100, 0x01},
+
+ {IMX135_TABLE_WAIT_MS, IMX135_WAIT_MS},
+ {IMX135_TABLE_END, 0x00}
+};
+
+static struct imx135_reg mode_quality_hdr[] = {
+ /* defect correction */
+ {0x380A, 0x00},
+ {0x380B, 0x00},
+ {0x4103, 0x00},
+ /* color artifact */
+ {0x4243, 0x9A},
+ {0x4330, 0x01},
+ {0x4331, 0x90},
+ {0x4332, 0x02},
+ {0x4333, 0x58},
+ {0x4334, 0x03},
+ {0x4335, 0x20},
+ {0x4336, 0x03},
+ {0x4337, 0x84},
+ {0x433C, 0x01},
+ {0x4340, 0x02},
+ {0x4341, 0x58},
+ {0x4342, 0x03},
+ {0x4343, 0x52},
+ /* moire reduction */
+ {0x4364, 0x0B},
+ {0x4368, 0x00},
+ {0x4369, 0x0F},
+ {0x436A, 0x03},
+ {0x436B, 0xA8},
+ {0x436C, 0x00},
+ {0x436D, 0x00},
+ {0x436E, 0x00},
+ {0x436F, 0x06},
+ /* CNR parameter */
+ {0x4281, 0x21},
+ {0x4282, 0x18},
+ {0x4283, 0x04},
+ {0x4284, 0x08},
+ {0x4287, 0x7F},
+ {0x4288, 0x08},
+ {0x428B, 0x7F},
+ {0x428C, 0x08},
+ {0x428F, 0x7F},
+ {0x4297, 0x00},
+ {0x4298, 0x7E},
+ {0x4299, 0x7E},
+ {0x429A, 0x7E},
+ {0x42A4, 0xFB},
+ {0x42A5, 0x7E},
+ {0x42A6, 0xDF},
+ {0x42A7, 0xB7},
+ {0x42AF, 0x03},
+
+ /* ARNR Parameter Settings */
+ {0x4207, 0x03},
+ {0x4216, 0x08},
+ {0x4217, 0x08},
+
+ /* DLC parameter */
+ {0x4218, 0x00},
+ {0x421B, 0x20},
+ {0x421F, 0x04},
+ {0x4222, 0x02},
+ {0x4223, 0x22},
+ {0x422E, 0x54},
+ {0x422F, 0xFB},
+ {0x4230, 0xFF},
+ {0x4231, 0xFE},
+ {0x4232, 0xFF},
+ {0x4235, 0x58},
+ {0x4236, 0xF7},
+ {0x4237, 0xFD},
+ {0x4239, 0x4E},
+ {0x423A, 0xFC},
+ {0x423B, 0xFD},
+
+ /* HDR Setting */
+ {0x4300, 0x00},
+ {0x4316, 0x12},
+ {0x4317, 0x22},
+ {0x4318, 0x00},
+ {0x4319, 0x00},
+ {0x431A, 0x00},
+ {0x4324, 0x03},
+ {0x4325, 0x20},
+ {0x4326, 0x03},
+ {0x4327, 0x84},
+ {0x4328, 0x03},
+ {0x4329, 0x20},
+ {0x432A, 0x03},
+ {0x432B, 0x20},
+ {0x432C, 0x01},
+ {0x432D, 0x01},
+ {0x4338, 0x02},
+ {0x4339, 0x00},
+ {0x433A, 0x00},
+ {0x433B, 0x02},
+ {0x435A, 0x03},
+ {0x435B, 0x84},
+ {0x435E, 0x01},
+ {0x435F, 0xFF},
+ {0x4360, 0x01},
+ {0x4361, 0xF4},
+ {0x4362, 0x03},
+ {0x4363, 0x84},
+ {0x437B, 0x01},
+ {0x4401, 0x3F},
+ {0x4402, 0xFF},
+ {0x4404, 0x13},
+ {0x4405, 0x26},
+ {0x4406, 0x07},
+ {0x4408, 0x20},
+ {0x4409, 0xE5},
+ {0x440A, 0xFB},
+ {0x440C, 0xF6},
+ {0x440D, 0xEA},
+ {0x440E, 0x20},
+ {0x4410, 0x00},
+ {0x4411, 0x00},
+ {0x4412, 0x3F},
+ {0x4413, 0xFF},
+ {0x4414, 0x1F},
+ {0x4415, 0xFF},
+ {0x4416, 0x20},
+ {0x4417, 0x00},
+ {0x4418, 0x1F},
+ {0x4419, 0xFF},
+ {0x441A, 0x20},
+ {0x441B, 0x00},
+ {0x441D, 0x40},
+ {0x441E, 0x1E},
+ {0x441F, 0x38},
+ {0x4420, 0x01},
+ {0x4444, 0x00},
+ {0x4445, 0x00},
+ {0x4446, 0x1D},
+ {0x4447, 0xF9},
+ {0x4452, 0x00},
+ {0x4453, 0xA0},
+ {0x4454, 0x08},
+ {0x4455, 0x00},
+ {0x4456, 0x0F},
+ {0x4457, 0xFF},
+ {0x4458, 0x18},
+ {0x4459, 0x18},
+ {0x445A, 0x3F},
+ {0x445B, 0x3A},
+ {0x445C, 0x00},
+ {0x445D, 0x28},
+ {0x445E, 0x01},
+ {0x445F, 0x90},
+ {0x4460, 0x00},
+ {0x4461, 0x60},
+ {0x4462, 0x00},
+ {0x4463, 0x00},
+ {0x4464, 0x00},
+ {0x4465, 0x00},
+ {0x446C, 0x01},
+ {0x446D, 0x00},
+ {0x446E, 0x00},
+
+ /* LSC setting */
+ {0x452A, 0x02},
+
+ /* White balance */
+ {0x0712, 0x01},
+ {0x0713, 0x00},
+ {0x0714, 0x01},
+ {0x0715, 0x00},
+ {0x0716, 0x01},
+ {0x0717, 0x00},
+ {0x0718, 0x01},
+ {0x0719, 0x00},
+
+ /* Shading */
+ {0x4500, 0x1F},
+
+ {IMX135_TABLE_WAIT_MS, IMX135_WAIT_MS},
+ {IMX135_TABLE_END, 0x00}
+};
+
+static struct imx135_reg mode_quality[] = {
+ /* defect correction */
+ {0x380A, 0x00},
+ {0x380B, 0x00},
+ {0x4103, 0x00},
+ /* color artifact */
+ {0x4243, 0x9A},
+ {0x4330, 0x01},
+ {0x4331, 0x90},
+ {0x4332, 0x02},
+ {0x4333, 0x58},
+ {0x4334, 0x03},
+ {0x4335, 0x20},
+ {0x4336, 0x03},
+ {0x4337, 0x84},
+ {0x433C, 0x01},
+ {0x4340, 0x02},
+ {0x4341, 0x58},
+ {0x4342, 0x03},
+ {0x4343, 0x52},
+ /* moire reduction */
+ {0x4364, 0x0B},
+ {0x4368, 0x00},
+ {0x4369, 0x0F},
+ {0x436A, 0x03},
+ {0x436B, 0xA8},
+ {0x436C, 0x00},
+ {0x436D, 0x00},
+ {0x436E, 0x00},
+ {0x436F, 0x06},
+ /* CNR parameter */
+ {0x4281, 0x21},
+ {0x4282, 0x18},
+ {0x4283, 0x04},
+ {0x4284, 0x08},
+ {0x4287, 0x7F},
+ {0x4288, 0x08},
+ {0x428B, 0x7F},
+ {0x428C, 0x08},
+ {0x428F, 0x7F},
+ {0x4297, 0x00},
+ {0x4298, 0x7E},
+ {0x4299, 0x7E},
+ {0x429A, 0x7E},
+ {0x42A4, 0xFB},
+ {0x42A5, 0x7E},
+ {0x42A6, 0xDF},
+ {0x42A7, 0xB7},
+ {0x42AF, 0x03},
+
+ /* ARNR Parameter Settings */
+ {0x4207, 0x03},
+ {0x4216, 0x08},
+ {0x4217, 0x08},
+
+ /* DLC parameter */
+ {0x4218, 0x00},
+ {0x421B, 0x20},
+ {0x421F, 0x04},
+ {0x4222, 0x02},
+ {0x4223, 0x22},
+ {0x422E, 0x54},
+ {0x422F, 0xFB},
+ {0x4230, 0xFF},
+ {0x4231, 0xFE},
+ {0x4232, 0xFF},
+ {0x4235, 0x58},
+ {0x4236, 0xF7},
+ {0x4237, 0xFD},
+ {0x4239, 0x4E},
+ {0x423A, 0xFC},
+ {0x423B, 0xFD},
+
+ /* HDR Setting */
+ {0x4300, 0x00},
+ {0x4316, 0x12},
+ {0x4317, 0x22},
+ {0x4318, 0x00},
+ {0x4319, 0x00},
+ {0x431A, 0x00},
+ {0x4324, 0x03},
+ {0x4325, 0x20},
+ {0x4326, 0x03},
+ {0x4327, 0x84},
+ {0x4328, 0x03},
+ {0x4329, 0x20},
+ {0x432A, 0x03},
+ {0x432B, 0x20},
+ {0x432C, 0x01},
+ {0x432D, 0x01},
+ {0x4338, 0x02},
+ {0x4339, 0x00},
+ {0x433A, 0x00},
+ {0x433B, 0x02},
+ {0x435A, 0x03},
+ {0x435B, 0x84},
+ {0x435E, 0x01},
+ {0x435F, 0xFF},
+ {0x4360, 0x01},
+ {0x4361, 0xF4},
+ {0x4362, 0x03},
+ {0x4363, 0x84},
+ {0x437B, 0x01},
+ {0x4401, 0x3F},
+ {0x4402, 0xFF},
+ {0x4404, 0x13},
+ {0x4405, 0x26},
+ {0x4406, 0x07},
+ {0x4408, 0x20},
+ {0x4409, 0xE5},
+ {0x440A, 0xFB},
+ {0x440C, 0xF6},
+ {0x440D, 0xEA},
+ {0x440E, 0x20},
+ {0x4410, 0x00},
+ {0x4411, 0x00},
+ {0x4412, 0x3F},
+ {0x4413, 0xFF},
+ {0x4414, 0x1F},
+ {0x4415, 0xFF},
+ {0x4416, 0x20},
+ {0x4417, 0x00},
+ {0x4418, 0x1F},
+ {0x4419, 0xFF},
+ {0x441A, 0x20},
+ {0x441B, 0x00},
+ {0x441D, 0x40},
+ {0x441E, 0x1E},
+ {0x441F, 0x38},
+ {0x4420, 0x01},
+ {0x4444, 0x00},
+ {0x4445, 0x00},
+ {0x4446, 0x1D},
+ {0x4447, 0xF9},
+ {0x4452, 0x00},
+ {0x4453, 0xA0},
+ {0x4454, 0x08},
+ {0x4455, 0x00},
+ {0x4456, 0x0F},
+ {0x4457, 0xFF},
+ {0x4458, 0x18},
+ {0x4459, 0x18},
+ {0x445A, 0x3F},
+ {0x445B, 0x3A},
+ {0x445C, 0x00},
+ {0x445D, 0x28},
+ {0x445E, 0x01},
+ {0x445F, 0x90},
+ {0x4460, 0x00},
+ {0x4461, 0x60},
+ {0x4462, 0x00},
+ {0x4463, 0x00},
+ {0x4464, 0x00},
+ {0x4465, 0x00},
+ {0x446C, 0x01},
+ {0x446D, 0x00},
+ {0x446E, 0x00},
+
+ /* LSC setting */
+ {0x452A, 0x02},
+
+ /* White balance */
+ {0x0712, 0x01},
+ {0x0713, 0x00},
+ {0x0714, 0x01},
+ {0x0715, 0x00},
+ {0x0716, 0x01},
+ {0x0717, 0x00},
+ {0x0718, 0x01},
+ {0x0719, 0x00},
+
+ /* Shading */
+ {0x4500, 0x1F},
+
+ {IMX135_TABLE_WAIT_MS, IMX135_WAIT_MS},
+ {IMX135_TABLE_END, 0x00}
+};
+
+enum {
+ IMX135_MODE_4208X3120,
+ IMX135_MODE_1920X1080,
+ IMX135_MODE_1280X720,
+ IMX135_MODE_2616X1472,
+ IMX135_MODE_3896X2192,
+ IMX135_MODE_QUALITY_HDR,
+ IMX135_MODE_QUALITY,
+};
+
+static struct imx135_reg *mode_table[] = {
+ [IMX135_MODE_4208X3120] = mode_4208x3120,
+ [IMX135_MODE_1920X1080] = mode_1920x1080,
+ [IMX135_MODE_1280X720] = mode_1280x720,
+ [IMX135_MODE_2616X1472] = mode_2616x1472,
+ [IMX135_MODE_3896X2192] = mode_3896x2192,
+ [IMX135_MODE_QUALITY_HDR] = mode_quality_hdr,
+ [IMX135_MODE_QUALITY] = mode_quality,
+};
+
+static inline void
+msleep_range(unsigned int delay_base)
+{
+ usleep_range(delay_base*1000, delay_base*1000+500);
+}
+
+static inline void
+imx135_get_frame_length_regs(struct imx135_reg *regs, u32 frame_length)
+{
+ regs->addr = 0x0340;
+ regs->val = (frame_length >> 8) & 0xff;
+ (regs + 1)->addr = 0x0341;
+ (regs + 1)->val = (frame_length) & 0xff;
+}
+
+static inline void
+imx135_get_coarse_time_regs(struct imx135_reg *regs, u32 coarse_time)
+{
+ regs->addr = 0x202;
+ regs->val = (coarse_time >> 8) & 0xff;
+ (regs + 1)->addr = 0x203;
+ (regs + 1)->val = (coarse_time) & 0xff;
+}
+
+static inline void
+imx135_get_coarse_time_short_regs(struct imx135_reg *regs, u32 coarse_time)
+{
+ regs->addr = 0x230;
+ regs->val = (coarse_time >> 8) & 0xff;
+ (regs + 1)->addr = 0x231;
+ (regs + 1)->val = (coarse_time) & 0xff;
+}
+
+static inline void
+imx135_get_gain_reg(struct imx135_reg *regs, u16 gain)
+{
+ regs->addr = 0x205;
+ regs->val = gain;
+}
+
+static inline void
+imx135_get_gain_short_reg(struct imx135_reg *regs, u16 gain)
+{
+ regs->addr = 0x233;
+ regs->val = gain;
+}
+
+static int
+imx135_read_reg(struct i2c_client *client, u16 addr, u8 *val)
+{
+ int err;
+ struct i2c_msg msg[2];
+ unsigned char data[3];
+
+ if (!client->adapter)
+ return -ENODEV;
+
+ msg[0].addr = client->addr;
+ msg[0].flags = 0;
+ msg[0].len = 2;
+ msg[0].buf = data;
+
+ /* high byte goes out first */
+ data[0] = (u8) (addr >> 8);
+ data[1] = (u8) (addr & 0xff);
+
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = 1;
+ msg[1].buf = data + 2;
+
+ err = i2c_transfer(client->adapter, msg, 2);
+
+ if (err != 2)
+ return -EINVAL;
+
+ *val = data[2];
+ return 0;
+}
+
+static int
+imx135_write_reg(struct i2c_client *client, u16 addr, u8 val)
+{
+ int err;
+ struct i2c_msg msg;
+ unsigned char data[3];
+
+ if (!client->adapter)
+ return -ENODEV;
+
+ data[0] = (u8) (addr >> 8);
+ data[1] = (u8) (addr & 0xff);
+ data[2] = (u8) (val & 0xff);
+
+ msg.addr = client->addr;
+ msg.flags = 0;
+ msg.len = 3;
+ msg.buf = data;
+
+ err = i2c_transfer(client->adapter, &msg, 1);
+ if (err == 1)
+ return 0;
+
+ pr_err("%s:i2c write failed, %x = %x\n",
+ __func__, addr, val);
+
+ return err;
+}
+
+static int
+imx135_write_table(struct i2c_client *client,
+ const struct imx135_reg table[],
+ const struct imx135_reg override_list[],
+ int num_override_regs)
+{
+ int err;
+ const struct imx135_reg *next;
+ int i;
+ u16 val;
+
+ for (next = table; next->addr != IMX135_TABLE_END; next++) {
+ if (next->addr == IMX135_TABLE_WAIT_MS) {
+ msleep_range(next->val);
+ continue;
+ }
+
+ val = next->val;
+
+ /* When an override list is passed in, replace the reg */
+ /* value to write if the reg is in the list */
+ if (override_list) {
+ for (i = 0; i < num_override_regs; i++) {
+ if (next->addr == override_list[i].addr) {
+ val = override_list[i].val;
+ break;
+ }
+ }
+ }
+
+ err = imx135_write_reg(client, next->addr, val);
+ if (err) {
+ pr_err("%s:imx135_write_table:%d", __func__, err);
+ return err;
+ }
+ }
+ return 0;
+}
+
+static int
+imx135_set_mode(struct imx135_info *info, struct imx135_mode *mode)
+{
+ int sensor_mode;
+ u8 quality_hdr;
+ int err;
+ struct imx135_reg reg_list[8];
+
+ pr_info("%s: xres %u yres %u framelength %u coarsetime %u gain %u, hdr %d\n",
+ __func__, mode->xres, mode->yres, mode->frame_length,
+ mode->coarse_time, mode->gain, mode->hdr_en);
+
+ if (mode->xres == 4208 && mode->yres == 3120) {
+ sensor_mode = IMX135_MODE_4208X3120;
+ quality_hdr = 1;
+ } else if (mode->xres == 1920 && mode->yres == 1080) {
+ sensor_mode = IMX135_MODE_1920X1080;
+ quality_hdr = 0;
+ } else if (mode->xres == 1280 && mode->yres == 720) {
+ sensor_mode = IMX135_MODE_1280X720;
+ quality_hdr = 0;
+ } else if (mode->xres == 2616 && mode->yres == 1472) {
+ sensor_mode = IMX135_MODE_2616X1472;
+ quality_hdr = 1;
+ } else if (mode->xres == 3896 && mode->yres == 2192) {
+ sensor_mode = IMX135_MODE_3896X2192;
+ quality_hdr = 1;
+ } else {
+ pr_err("%s: invalid resolution supplied to set mode %d %d\n",
+ __func__, mode->xres, mode->yres);
+ return -EINVAL;
+ }
+
+ /* get a list of override regs for the asking frame length, */
+ /* coarse integration time, and gain. */
+ imx135_get_frame_length_regs(reg_list, mode->frame_length);
+ imx135_get_coarse_time_regs(reg_list + 2, mode->coarse_time);
+ imx135_get_gain_reg(reg_list + 4, mode->gain);
+ if (mode->hdr_en == 1) /* if HDR is enabled */
+ {
+ imx135_get_gain_short_reg(reg_list + 5, mode->gain);
+ imx135_get_coarse_time_short_regs(
+ reg_list + 6, mode->coarse_time_short);
+ }
+
+ err = imx135_write_table(info->i2c_client,
+ mode_table[sensor_mode],
+ reg_list, mode->hdr_en ? 8 : 5);
+ if (err)
+ return err;
+ if (quality_hdr)
+ err = imx135_write_table(info->i2c_client,
+ mode_table[IMX135_MODE_QUALITY_HDR],
+ reg_list, 0);
+ else
+ err = imx135_write_table(info->i2c_client,
+ mode_table[IMX135_MODE_QUALITY],
+ reg_list, 0);
+ if (err)
+ return err;
+
+ info->mode = sensor_mode;
+ pr_info("[IMX135]: stream on.\n");
+ return 0;
+}
+
+static int
+imx135_get_status(struct imx135_info *info, u8 *dev_status)
+{
+ *dev_status = 0;
+ return 0;
+}
+
+static int
+imx135_set_frame_length(struct imx135_info *info, u32 frame_length,
+ bool group_hold)
+{
+ struct imx135_reg reg_list[2];
+ int i = 0;
+ int ret;
+
+ imx135_get_frame_length_regs(reg_list, frame_length);
+
+ if (group_hold) {
+ ret = imx135_write_reg(info->i2c_client, 0x0104, 0x01);
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0; i < 2; i++) {
+ ret = imx135_write_reg(info->i2c_client, reg_list[i].addr,
+ reg_list[i].val);
+ if (ret)
+ return ret;
+ }
+
+ if (group_hold) {
+ ret = imx135_write_reg(info->i2c_client, 0x0104, 0x0);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+imx135_set_coarse_time(struct imx135_info *info, u32 coarse_time,
+ bool group_hold)
+{
+ int ret;
+
+ struct imx135_reg reg_list[2];
+ int i = 0;
+
+ imx135_get_coarse_time_regs(reg_list, coarse_time);
+
+ if (group_hold) {
+ ret = imx135_write_reg(info->i2c_client, 0x104, 0x01);
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0; i < 2; i++) {
+ ret = imx135_write_reg(info->i2c_client, reg_list[i].addr,
+ reg_list[i].val);
+ if (ret)
+ return ret;
+ }
+
+ if (group_hold) {
+ ret = imx135_write_reg(info->i2c_client, 0x104, 0x0);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+static int
+imx135_set_gain(struct imx135_info *info, u16 gain, bool group_hold)
+{
+ int ret;
+ struct imx135_reg reg_list;
+
+ imx135_get_gain_reg(&reg_list, gain);
+
+ if (group_hold) {
+ ret = imx135_write_reg(info->i2c_client, 0x104, 0x1);
+ if (ret)
+ return ret;
+ }
+
+ ret = imx135_write_reg(info->i2c_client, reg_list.addr, reg_list.val);
+ /* writing second gain register for HDR */
+ ret = imx135_write_reg(info->i2c_client, 0x233, reg_list.val);
+ if (ret)
+ return ret;
+
+ if (group_hold) {
+ ret = imx135_write_reg(info->i2c_client, 0x104, 0x0);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+static int
+imx135_set_hdr_coarse_time(struct imx135_info *info, struct imx135_hdr *values)
+{
+ struct imx135_reg reg_list[2];
+ struct imx135_reg reg_list_short[2];
+ int ret, i = 0;
+
+ /* get long and short coarse time registers */
+ imx135_get_coarse_time_regs(reg_list, values->coarse_time_long);
+ imx135_get_coarse_time_short_regs(reg_list_short,
+ values->coarse_time_short);
+ /* set to direct mode */
+ ret = imx135_write_reg(info->i2c_client, 0x238, 0x1);
+ if (ret)
+ return ret;
+ /* set group hold */
+ ret = imx135_write_reg(info->i2c_client, 0x104, 0x1);
+ if (ret)
+ return ret;
+ /* writing long exposure */
+ for (i = 0; i < 2; i++) {
+ ret = imx135_write_reg(info->i2c_client, reg_list[i].addr,
+ reg_list[i].val);
+ if (ret)
+ return ret;
+ }
+ /* writing short exposure */
+ for (i = 0; i < 2; i++) {
+ ret = imx135_write_reg(info->i2c_client, reg_list_short[i].addr,
+ reg_list_short[i].val);
+ if (ret)
+ return ret;
+ }
+ ret = imx135_write_reg(info->i2c_client, 0x104, 0x0);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int
+imx135_set_group_hold(struct imx135_info *info, struct imx135_ae *ae)
+{
+ int ret;
+ int count = 0;
+ bool groupHoldEnabled = false;
+ struct imx135_hdr values;
+
+ values.coarse_time_long = ae->coarse_time;
+ values.coarse_time_short = ae->coarse_time_short;
+
+ if (ae->gain_enable)
+ count++;
+ if (ae->coarse_time_enable)
+ count++;
+ if (ae->frame_length_enable)
+ count++;
+ if (count >= 2)
+ groupHoldEnabled = true;
+
+ if (groupHoldEnabled) {
+ ret = imx135_write_reg(info->i2c_client, 0x104, 0x1);
+ if (ret)
+ return ret;
+ }
+
+ if (ae->gain_enable)
+ imx135_set_gain(info, ae->gain, false);
+ if (ae->coarse_time_enable)
+ imx135_set_hdr_coarse_time(info, &values);
+ if (ae->frame_length_enable)
+ imx135_set_frame_length(info, ae->frame_length, false);
+
+ if (groupHoldEnabled) {
+ ret = imx135_write_reg(info->i2c_client, 0x104, 0x0);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int imx135_get_sensor_id(struct imx135_info *info)
+{
+ int ret = 0;
+ int i;
+ u8 bak = 0;
+
+ pr_info("%s\n", __func__);
+ if (info->sensor_data.fuse_id_size)
+ return 0;
+
+ /* Note 1: If the sensor does not have power at this point
+ Need to supply the power, e.g. by calling power on function */
+
+ ret |= imx135_write_reg(info->i2c_client, 0x3B02, 0x00);
+ ret |= imx135_write_reg(info->i2c_client, 0x3B00, 0x01);
+ for (i = 0; i < 9 ; i++) {
+ ret |= imx135_read_reg(info->i2c_client, 0x3B24 + i, &bak);
+ info->sensor_data.fuse_id[i] = bak;
+ }
+
+ if (!ret)
+ info->sensor_data.fuse_id_size = i;
+
+ /* Note 2: Need to clean up any action carried out in Note 1 */
+
+ return ret;
+}
+
+static long
+imx135_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int err;
+ struct imx135_info *info = file->private_data;
+
+ switch (cmd) {
+ case IMX135_IOCTL_SET_MODE:
+ {
+ struct imx135_mode mode;
+ if (copy_from_user(&mode, (const void __user *)arg,
+ sizeof(struct imx135_mode))) {
+ pr_err("%s:Failed to get mode from user.\n", __func__);
+ return -EFAULT;
+ }
+ return imx135_set_mode(info, &mode);
+ }
+ case IMX135_IOCTL_SET_FRAME_LENGTH:
+ return imx135_set_frame_length(info, (u32)arg, true);
+ case IMX135_IOCTL_SET_COARSE_TIME:
+ return imx135_set_coarse_time(info, (u32)arg, true);
+ case IMX135_IOCTL_SET_GAIN:
+ return imx135_set_gain(info, (u16)arg, true);
+ case IMX135_IOCTL_GET_STATUS:
+ {
+ u8 status;
+
+ err = imx135_get_status(info, &status);
+ if (err)
+ return err;
+ if (copy_to_user((void __user *)arg, &status, 1)) {
+ pr_err("%s:Failed to copy status to user\n", __func__);
+ return -EFAULT;
+ }
+ return 0;
+ }
+ case IMX135_IOCTL_GET_SENSORDATA:
+ {
+ err = imx135_get_sensor_id(info);
+
+ if (err) {
+ pr_err("%s:Failed to get fuse id info.\n", __func__);
+ return err;
+ }
+ if (copy_to_user((void __user *)arg, &info->sensor_data,
+ sizeof(struct imx135_sensordata))) {
+ pr_info("%s:Failed to copy fuse id to user space\n",
+ __func__);
+ return -EFAULT;
+ }
+ return 0;
+ }
+ case IMX135_IOCTL_SET_GROUP_HOLD:
+ {
+ struct imx135_ae ae;
+ if (copy_from_user(&ae, (const void __user *)arg,
+ sizeof(struct imx135_ae))) {
+ pr_info("%s:fail group hold\n", __func__);
+ return -EFAULT;
+ }
+ return imx135_set_group_hold(info, &ae);
+ }
+ case IMX135_IOCTL_SET_HDR_COARSE_TIME:
+ {
+ struct imx135_hdr values;
+
+ dev_dbg(&info->i2c_client->dev,
+ "IMX135_IOCTL_SET_HDR_COARSE_TIME\n");
+ if (copy_from_user(&values,
+ (const void __user *)arg,
+ sizeof(struct imx135_hdr))) {
+ err = -EFAULT;
+ break;
+ }
+ err = imx135_set_hdr_coarse_time(info, &values);
+ break;
+ }
+ default:
+ pr_err("%s:unknown cmd.\n", __func__);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int imx135_debugfs_show(struct seq_file *s, void *unused)
+{
+ struct imx135_info *dev = s->private;
+
+ dev_dbg(&dev->i2c_client->dev, "%s: ++\n", __func__);
+
+ mutex_lock(&dev->imx135_camera_lock);
+ mutex_unlock(&dev->imx135_camera_lock);
+
+ return 0;
+}
+
+static ssize_t imx135_debugfs_write(
+ struct file *file,
+ char const __user *buf,
+ size_t count,
+ loff_t *offset)
+{
+ struct imx135_info *dev =
+ ((struct seq_file *)file->private_data)->private;
+ struct i2c_client *i2c_client = dev->i2c_client;
+ int ret = 0;
+ char buffer[24];
+ u32 address;
+ u32 data;
+ u8 readback;
+
+ dev_dbg(&i2c_client->dev, "%s: ++\n", __func__);
+
+ if (copy_from_user(&buffer, buf, sizeof(buffer)))
+ goto debugfs_write_fail;
+
+ if (sscanf(buf, "0x%x 0x%x", &address, &data) == 2)
+ goto set_attr;
+ if (sscanf(buf, "0X%x 0X%x", &address, &data) == 2)
+ goto set_attr;
+ if (sscanf(buf, "%d %d", &address, &data) == 2)
+ goto set_attr;
+
+ if (sscanf(buf, "0x%x 0x%x", &address, &data) == 1)
+ goto read;
+ if (sscanf(buf, "0X%x 0X%x", &address, &data) == 1)
+ goto read;
+ if (sscanf(buf, "%d %d", &address, &data) == 1)
+ goto read;
+
+ dev_err(&i2c_client->dev, "SYNTAX ERROR: %s\n", buf);
+ return -EFAULT;
+
+set_attr:
+ dev_info(&i2c_client->dev,
+ "new address = %x, data = %x\n", address, data);
+ ret |= imx135_write_reg(i2c_client, address, data);
+read:
+ ret |= imx135_read_reg(i2c_client, address, &readback);
+ dev_dbg(&i2c_client->dev,
+ "wrote to address 0x%x with value 0x%x\n",
+ address, readback);
+
+ if (ret)
+ goto debugfs_write_fail;
+
+ return count;
+
+debugfs_write_fail:
+ dev_err(&i2c_client->dev,
+ "%s: test pattern write failed\n", __func__);
+ return -EFAULT;
+}
+
+static int imx135_debugfs_open(struct inode *inode, struct file *file)
+{
+ struct imx135_info *dev = inode->i_private;
+ struct i2c_client *i2c_client = dev->i2c_client;
+
+ dev_dbg(&i2c_client->dev, "%s: ++\n", __func__);
+
+ return single_open(file, imx135_debugfs_show, inode->i_private);
+}
+
+static const struct file_operations imx135_debugfs_fops = {
+ .open = imx135_debugfs_open,
+ .read = seq_read,
+ .write = imx135_debugfs_write,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static void imx135_remove_debugfs(struct imx135_info *dev)
+{
+ struct i2c_client *i2c_client = dev->i2c_client;
+
+ dev_dbg(&i2c_client->dev, "%s: ++\n", __func__);
+
+ if (dev->debugdir)
+ debugfs_remove_recursive(dev->debugdir);
+ dev->debugdir = NULL;
+}
+
+static void imx135_create_debugfs(struct imx135_info *dev)
+{
+ struct dentry *ret;
+ struct i2c_client *i2c_client = dev->i2c_client;
+
+ dev_dbg(&i2c_client->dev, "%s\n", __func__);
+
+ dev->debugdir =
+ debugfs_create_dir(dev->miscdev_info.this_device->kobj.name,
+ NULL);
+ if (!dev->debugdir)
+ goto remove_debugfs;
+
+ ret = debugfs_create_file("d",
+ S_IWUSR | S_IRUGO,
+ dev->debugdir, dev,
+ &imx135_debugfs_fops);
+ if (!ret)
+ goto remove_debugfs;
+
+ return;
+remove_debugfs:
+ dev_err(&i2c_client->dev, "couldn't create debugfs\n");
+ imx135_remove_debugfs(dev);
+}
+
+static int
+imx135_open(struct inode *inode, struct file *file)
+{
+ struct miscdevice *miscdev = file->private_data;
+ struct imx135_info *info;
+
+ info = container_of(miscdev, struct imx135_info, miscdev_info);
+ /* check if the device is in use */
+ if (atomic_xchg(&info->in_use, 1)) {
+ pr_info("%s:BUSY!\n", __func__);
+ return -EBUSY;
+ }
+
+ file->private_data = info;
+
+ if (info->pdata && info->pdata->power_on)
+ info->pdata->power_on(&info->power);
+ else{
+ pr_err("%s:no valid power_on function.\n", __func__);
+ return -EEXIST;
+ }
+
+ return 0;
+}
+
+static int
+imx135_release(struct inode *inode, struct file *file)
+{
+ struct imx135_info *info = file->private_data;
+
+ if (info->pdata && info->pdata->power_off)
+ info->pdata->power_off(&info->power);
+ file->private_data = NULL;
+
+ /* warn if device is already released */
+ WARN_ON(!atomic_xchg(&info->in_use, 0));
+ return 0;
+}
+
+static int imx135_power_put(struct imx135_power_rail *pw)
+{
+ if (unlikely(!pw))
+ return -EFAULT;
+
+ if (likely(pw->avdd))
+ regulator_put(pw->avdd);
+
+ if (likely(pw->iovdd))
+ regulator_put(pw->iovdd);
+
+ if (likely(pw->dvdd))
+ regulator_put(pw->dvdd);
+
+ pw->avdd = NULL;
+ pw->iovdd = NULL;
+ pw->dvdd = NULL;
+
+ return 0;
+}
+
+static int imx135_regulator_get(struct imx135_info *info,
+ struct regulator **vreg, char vreg_name[])
+{
+ struct regulator *reg = NULL;
+ int err = 0;
+
+ reg = regulator_get(&info->i2c_client->dev, vreg_name);
+ if (unlikely(IS_ERR_OR_NULL(reg))) {
+ dev_err(&info->i2c_client->dev, "%s %s ERR: %d\n",
+ __func__, vreg_name, (int)reg);
+ err = PTR_ERR(reg);
+ reg = NULL;
+ } else
+ dev_dbg(&info->i2c_client->dev, "%s: %s\n",
+ __func__, vreg_name);
+
+ *vreg = reg;
+ return err;
+}
+
+static int imx135_power_get(struct imx135_info *info)
+{
+ struct imx135_power_rail *pw = &info->power;
+
+ imx135_regulator_get(info, &pw->avdd, "vana"); /* ananlog 2.7v */
+ imx135_regulator_get(info, &pw->dvdd, "vdig"); /* digital 1.2v */
+ imx135_regulator_get(info, &pw->iovdd, "vif"); /* interface 1.8v */
+
+ return 0;
+}
+
+static const struct file_operations imx135_fileops = {
+ .owner = THIS_MODULE,
+ .open = imx135_open,
+ .unlocked_ioctl = imx135_ioctl,
+ .release = imx135_release,
+};
+
+static struct miscdevice imx135_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "imx135",
+ .fops = &imx135_fileops,
+};
+
+
+static int
+imx135_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct imx135_info *info;
+ int err;
+
+ pr_info("[IMX135]: probing sensor.\n");
+
+ info = devm_kzalloc(&client->dev,
+ sizeof(struct imx135_info), GFP_KERNEL);
+ if (!info) {
+ pr_err("%s:Unable to allocate memory!\n", __func__);
+ return -ENOMEM;
+ }
+
+ info->pdata = client->dev.platform_data;
+ info->i2c_client = client;
+ atomic_set(&info->in_use, 0);
+ info->mode = -1;
+
+ imx135_power_get(info);
+
+ memcpy(&info->miscdev_info,
+ &imx135_device,
+ sizeof(struct miscdevice));
+
+ err = misc_register(&info->miscdev_info);
+ if (err) {
+ pr_err("%s:Unable to register misc device!\n", __func__);
+ goto imx135_probe_fail;
+ }
+
+ i2c_set_clientdata(client, info);
+ /* create debugfs interface */
+ imx135_create_debugfs(info);
+ return 0;
+
+imx135_probe_fail:
+ imx135_power_put(&info->power);
+
+ return err;
+}
+
+static int
+imx135_remove(struct i2c_client *client)
+{
+ struct imx135_info *info;
+ info = i2c_get_clientdata(client);
+ misc_deregister(&imx135_device);
+
+ imx135_power_put(&info->power);
+
+ imx135_remove_debugfs(info);
+ return 0;
+}
+
+static const struct i2c_device_id imx135_id[] = {
+ { "imx135", 0 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(i2c, imx135_id);
+
+static struct i2c_driver imx135_i2c_driver = {
+ .driver = {
+ .name = "imx135",
+ .owner = THIS_MODULE,
+ },
+ .probe = imx135_probe,
+ .remove = imx135_remove,
+ .id_table = imx135_id,
+};
+
+static int __init imx135_init(void)
+{
+ pr_info("[IMX135] sensor driver loading\n");
+ return i2c_add_driver(&imx135_i2c_driver);
+}
+
+static void __exit imx135_exit(void)
+{
+ i2c_del_driver(&imx135_i2c_driver);
+}
+
+module_init(imx135_init);
+module_exit(imx135_exit);
diff --git a/drivers/media/video/tegra/max77665-flash.c b/drivers/media/video/tegra/max77665-flash.c
index 15cf8897dfc0..2feee300eb42 100644
--- a/drivers/media/video/tegra/max77665-flash.c
+++ b/drivers/media/video/tegra/max77665-flash.c
@@ -1,7 +1,7 @@
/*
* MAX77665_F.c - MAX77665_F flash/torch kernel driver
*
- * Copyright (c) 2012-2013, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2012 - 2013, NVIDIA CORPORATION. All rights reserved.
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -65,7 +65,6 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/uaccess.h>
-#include <linux/list.h>
#include <linux/regulator/consumer.h>
#include <linux/gpio.h>
#include <linux/seq_file.h>
@@ -172,6 +171,8 @@
#define MAX77665_F_MAX_FLASH_LEVEL ((1 << 6) + 1)
#define MAX77665_F_MAX_TORCH_LEVEL ((1 << 4) + 1)
+#define MAX77665_F_LEVEL_OFF 0xFFFF
+
#define MAX77665_F_MAX_FLASH_CURRENT(x) \
DIV_ROUND_UP(((x) * MAX77665_F_MAX_FLASH_LEVEL), 1000)
#define MAX77665_F_MAX_TORCH_CURRENT(x) \
@@ -180,6 +181,9 @@
#define SUSTAINTIME_DEF 558
#define DEFAULT_FLASH_TMR_DUR ((SUSTAINTIME_DEF * 10 - 1) / 625)
+#define MAX77665_F_FLASH_TIMER_NUM 16
+#define MAX77665_F_TORCH_TIMER_NUM 17
+
/* minimium debounce time 600uS */
#define RECHARGEFACTOR_DEF 600
@@ -187,11 +191,27 @@
#define MAXFLASH_MODE_TORCH 1
#define MAXFLASH_MODE_FLASH 2
-#define max77665_f_max_flash_cap_size (sizeof(u32) \
- + (sizeof(struct nvc_torch_level_info) \
- * (MAX77665_F_MAX_FLASH_LEVEL)))
-#define max77665_f_max_torch_cap_size (sizeof(u32) \
- + (sizeof(s32) * (MAX77665_F_MAX_TORCH_LEVEL)))
+#define max77665_f_flash_cap_size \
+ (sizeof(struct nvc_torch_flash_capabilities_v1) \
+ + sizeof(struct nvc_torch_lumi_level_v1) \
+ * MAX77665_F_MAX_FLASH_LEVEL)
+#define max77665_f_flash_timeout_size \
+ (sizeof(struct nvc_torch_timer_capabilities_v1) \
+ + sizeof(struct nvc_torch_timeout_v1) \
+ * MAX77665_F_FLASH_TIMER_NUM)
+#define max77665_f_max_flash_cap_size (max77665_f_flash_cap_size * 2 \
+ + max77665_f_flash_timeout_size * 2)
+
+#define max77665_f_torch_cap_size \
+ (sizeof(struct nvc_torch_torch_capabilities_v1) \
+ + sizeof(struct nvc_torch_lumi_level_v1) \
+ * MAX77665_F_MAX_TORCH_LEVEL)
+#define max77665_f_torch_timeout_size \
+ (sizeof(struct nvc_torch_timer_capabilities_v1) \
+ + sizeof(struct nvc_torch_timeout_v1) \
+ * MAX77665_F_TORCH_TIMER_NUM)
+#define max77665_f_max_torch_cap_size (max77665_f_torch_timeout_size * 2\
+ + max77665_f_torch_timeout_size * 2)
#define GET_CURRENT_BY_INDEX(c) ((c) * 125 / 8) /* mul 15.625 mA */
#define GET_INDEX_BY_CURRENT(c) ((c) * 8 / 125) /* div by 15.625 mA */
@@ -230,13 +250,14 @@ struct max77665_f_info {
struct device *dev;
struct miscdevice miscdev;
struct dentry *d_max77665_f;
- struct list_head list;
- struct max77665_f_info *s_info;
struct mutex mutex;
struct max77665_f_power_rail pwr_rail;
struct max77665_f_platform_data *pdata;
- struct nvc_torch_flash_capabilities *flash_cap;
- struct nvc_torch_torch_capabilities *torch_cap;
+ struct nvc_torch_capability_query query;
+ struct nvc_torch_flash_capabilities_v1 *flash_cap[2];
+ struct nvc_torch_timer_capabilities_v1 *flash_timeouts[2];
+ struct nvc_torch_torch_capabilities_v1 *torch_cap[2];
+ struct nvc_torch_timer_capabilities_v1 *torch_timeouts[2];
struct max77665_f_config config;
struct max77665_f_reg_cache regs;
struct max77665_f_state_regs states;
@@ -246,13 +267,10 @@ struct max77665_f_info {
atomic_t in_use;
int flash_cap_size;
int torch_cap_size;
- int pwr_api;
- int pwr_dev;
- int sustainTime;
+ int pwr_state;
u8 fled_settings;
u8 op_mode;
u8 power_is_on;
- u8 s_mode;
u8 ftimer_mode;
u8 ttimer_mode;
u8 new_ftimer;
@@ -336,8 +354,15 @@ static struct max77665_f_platform_data max77665_f_default_pdata = {
.pinstate = {0x0000, 0x0000},
};
-static LIST_HEAD(max77665_f_info_list);
-static DEFINE_SPINLOCK(max77665_f_spinlock);
+/* torch timer duration settings in uS */
+#define MAX77665_F_TORCH_TIMER_FOREVER 0xFFFFFFFF
+static u32 max77665_f_torch_timer[] = {
+ 262000, 524000, 786000, 1048000,
+ 1572000, 2096000, 2620000, 3144000,
+ 4193000, 5242000, 6291000, 7340000,
+ 9437000, 11534000, 13631000, 15728000,
+ MAX77665_F_TORCH_TIMER_FOREVER
+};
static void max77665_f_throttle(unsigned int new_state, void *priv_data);
@@ -467,8 +492,10 @@ static int max77665_f_set_leds(struct max77665_f_info *info,
u8 mask, u8 curr1, u8 curr2)
{
int err = 0;
- u16 f_levels = info->flash_cap->numberoflevels - 2;
- u16 t_levels = info->torch_cap->numberoflevels - 2;
+ u32 f_levels1 = info->flash_cap[0]->numberoflevels - 2;
+ u32 f_levels2 = info->flash_cap[1]->numberoflevels - 2;
+ u32 t_levels1 = info->torch_cap[0]->numberoflevels - 2;
+ u32 t_levels2 = info->torch_cap[1]->numberoflevels - 2;
u8 fled_en = 0;
u8 t_curr = 0;
u8 regs[6];
@@ -490,13 +517,13 @@ static int max77665_f_set_leds(struct max77665_f_info *info,
if (mask & 1) {
if (info->op_mode == MAXFLASH_MODE_FLASH) {
- if (curr1 > f_levels)
- curr1 = f_levels;
+ if (curr1 > f_levels1)
+ curr1 = f_levels1;
fled_en |= (info->fled_settings & LED1_FLASH_TRIG_MASK);
regs[0] = curr1;
} else {
- if (curr1 > t_levels)
- curr1 = t_levels;
+ if (curr1 > t_levels1)
+ curr1 = t_levels1;
fled_en |= (info->fled_settings & LED1_TORCH_TRIG_MASK);
t_curr = curr1;
}
@@ -504,13 +531,13 @@ static int max77665_f_set_leds(struct max77665_f_info *info,
if (mask & 2) {
if (info->op_mode == MAXFLASH_MODE_FLASH) {
- if (curr2 > f_levels)
- curr2 = f_levels;
+ if (curr2 > f_levels2)
+ curr2 = f_levels2;
fled_en |= (info->fled_settings & LED2_FLASH_TRIG_MASK);
regs[1] = curr2;
} else {
- if (curr2 > t_levels)
- curr2 = t_levels;
+ if (curr2 > t_levels2)
+ curr2 = t_levels2;
fled_en |= (info->fled_settings & LED2_TORCH_TRIG_MASK);
t_curr |= curr2 << 4;
}
@@ -778,10 +805,12 @@ static int max77665_f_update_settings(struct max77665_f_info *info)
static int max77665_f_configure(struct max77665_f_info *info, bool update)
{
struct max77665_f_config *pcfg = &info->config;
- struct nvc_torch_flash_capabilities *pfcap = info->flash_cap;
- struct nvc_torch_torch_capabilities *ptcap = info->torch_cap;
- int val;
- int i;
+ struct nvc_torch_capability_query *pqry = &info->query;
+ struct nvc_torch_flash_capabilities_v1 *pfcap = NULL;
+ struct nvc_torch_torch_capabilities_v1 *ptcap = NULL;
+ struct nvc_torch_timer_capabilities_v1 *ptmcap = NULL;
+ struct nvc_torch_lumi_level_v1 *plvls = NULL;
+ int val, i, j;
if (pcfg->max_peak_current_mA > max77665_f_caps.max_peak_curr_mA ||
!pcfg->max_peak_current_mA) {
@@ -792,9 +821,14 @@ static int max77665_f_configure(struct max77665_f_info *info, bool update)
pcfg->max_peak_current_mA = max77665_f_caps.max_peak_curr_mA;
}
+ /* number of leds enabled */
i = 1;
- if ((info->config.led_mask & 3) == 3)
+ /* in synchronize mode, both leds are considered as 1 */
+ if (!pcfg->synchronized_led && (info->config.led_mask & 3) == 3)
i = 2;
+ pqry->flash_num = i;
+ pqry->torch_num = i;
+
val = pcfg->max_peak_current_mA * i;
if (val > max77665_f_caps.max_total_current_mA)
val = max77665_f_caps.max_total_current_mA;
@@ -814,37 +848,80 @@ static int max77665_f_configure(struct max77665_f_info *info, bool update)
max77665_f_caps.max_torch_curr_mA;
}
- pfcap->levels[0].guidenum = 0;
- pfcap->levels[0].sustaintime = 0xFFFFFFFF;
- pfcap->levels[0].rechargefactor = 0;
- val = max77665_f_caps.curr_step_uA;
- for (i = 1; i < MAX77665_F_MAX_FLASH_LEVEL; i++) {
- pfcap->levels[i].guidenum = val * i / 1000; /* mA */
- if (pfcap->levels[i].guidenum >
- pcfg->max_peak_current_mA) {
- pfcap->levels[i].guidenum = 0;
- break;
+ pqry->version = NVC_TORCH_CAPABILITY_VER_1;
+ pqry->led_attr = 0;
+ for (i = 0; i < pqry->flash_num; i++) {
+ pfcap = info->flash_cap[i];
+ pfcap->version = NVC_TORCH_CAPABILITY_VER_1;
+ pfcap->led_idx = i;
+ pfcap->attribute = 0;
+ pfcap->numberoflevels = pcfg->led_config[i].flash_levels + 1;
+ pfcap->granularity = pcfg->led_config[i].granularity;
+ pfcap->timeout_num = MAX77665_F_FLASH_TIMER_NUM;
+ ptmcap = info->flash_timeouts[i];
+ pfcap->timeout_off = (void *)ptmcap - (void *)pfcap;
+ pfcap->flash_torch_ratio =
+ pcfg->led_config[i].flash_torch_ratio;
+ dev_dbg(info->dev,
+ "%s flash#%d, attr: %x, levels: %d, g: %d, ratio: %d\n",
+ __func__, pfcap->led_idx, pfcap->attribute,
+ pfcap->numberoflevels, pfcap->granularity,
+ pfcap->flash_torch_ratio);
+
+ plvls = pcfg->led_config[i].lumi_levels;
+ pfcap->levels[0].guidenum = MAX77665_F_LEVEL_OFF;
+ pfcap->levels[0].luminance = 0;
+ for (j = 1; j < pfcap->numberoflevels; j++) {
+ pfcap->levels[j].guidenum = plvls[j - 1].guidenum;
+ pfcap->levels[j].luminance = plvls[j - 1].luminance;
+ dev_dbg(info->dev, "%02d - %d\n",
+ pfcap->levels[j].guidenum,
+ pfcap->levels[j].luminance);
+ }
+
+ ptmcap->timeout_num = pfcap->timeout_num;
+ for (j = 0; j < ptmcap->timeout_num; j++) {
+ ptmcap->timeouts[j].timeout = 62500 * (j + 1);
+ dev_dbg(info->dev, "t: %02d - %d uS\n", j,
+ ptmcap->timeouts[j].timeout);
}
- pfcap->levels[i].sustaintime = info->sustainTime;
- pfcap->levels[i].rechargefactor = RECHARGEFACTOR_DEF;
}
- info->flash_cap_size = (sizeof(u32) +
- (sizeof(struct nvc_torch_level_info) * i));
- pfcap->numberoflevels = i;
-
- ptcap->guidenum[0] = 0;
- for (i = 1; i < MAX77665_F_MAX_TORCH_LEVEL; i++) {
- ptcap->guidenum[i] = pfcap->levels[i].guidenum;
- if (ptcap->guidenum[i] > pcfg->max_torch_current_mA) {
- ptcap->guidenum[i] = 0;
- break;
+
+ for (i = 0; i < pqry->torch_num; i++) {
+ ptcap = info->torch_cap[i];
+ ptcap->version = NVC_TORCH_CAPABILITY_VER_1;
+ ptcap->led_idx = i;
+ ptcap->attribute = 0;
+ ptcap->numberoflevels = pcfg->led_config[i].flash_levels + 1;
+ ptcap->granularity = pcfg->led_config[i].granularity;
+ ptcap->timeout_num = MAX77665_F_TORCH_TIMER_NUM;
+ ptmcap = info->torch_timeouts[i];
+ ptcap->timeout_off = (void *)ptmcap - (void *)ptcap;
+ dev_dbg(info->dev, "torch#%d, attr: %x, levels: %d, g: %d\n",
+ ptcap->led_idx, ptcap->attribute,
+ ptcap->numberoflevels, ptcap->granularity);
+
+ plvls = pcfg->led_config[i].lumi_levels;
+ ptcap->levels[0].guidenum = MAX77665_F_LEVEL_OFF;
+ ptcap->levels[0].luminance = 0;
+ for (j = 1; j < ptcap->numberoflevels; j++) {
+ ptcap->levels[j].guidenum = plvls[j - 1].guidenum;
+ ptcap->levels[j].luminance = plvls[j - 1].luminance;
+ dev_dbg(info->dev, "%02d - %d\n",
+ ptcap->levels[j].guidenum,
+ ptcap->levels[j].luminance);
+ }
+
+ ptmcap->timeout_num = ptcap->timeout_num;
+ for (j = 0; j < ptmcap->timeout_num; j++) {
+ ptmcap->timeouts[j].timeout = max77665_f_torch_timer[j];
+ dev_dbg(info->dev, "t: %02d - %d uS\n", j,
+ ptmcap->timeouts[j].timeout);
}
}
- info->torch_cap_size = (sizeof(u32) + (sizeof(s32) * i));
- ptcap->numberoflevels = i;
- if (update && (info->pwr_dev == NVC_PWR_COMM ||
- info->pwr_dev == NVC_PWR_ON))
+ if (update && (info->pwr_state == NVC_PWR_COMM ||
+ info->pwr_state == NVC_PWR_ON))
return max77665_f_update_settings(info);
return 0;
@@ -1018,25 +1095,25 @@ max77665_f_poweron_vio_fail:
return err;
}
-static int max77665_f_power(struct max77665_f_info *info, int pwr)
+static int max77665_f_power_set(struct max77665_f_info *info, int pwr)
{
int err = 0;
- if (pwr == info->pwr_dev)
+ if (pwr == info->pwr_state)
return 0;
switch (pwr) {
case NVC_PWR_OFF:
max77665_f_enter_offmode(info, true);
if ((info->pdata->cfg & NVC_CFG_OFF2STDBY) ||
- (info->pdata->cfg & NVC_CFG_BOOT_INIT))
+ (info->pdata->cfg & NVC_CFG_BOOT_INIT))
pwr = NVC_PWR_STDBY;
else
err = max77665_f_power_off(info);
break;
case NVC_PWR_STDBY_OFF:
if ((info->pdata->cfg & NVC_CFG_OFF2STDBY) ||
- (info->pdata->cfg & NVC_CFG_BOOT_INIT))
+ (info->pdata->cfg & NVC_CFG_BOOT_INIT))
pwr = NVC_PWR_STDBY;
else
err = max77665_f_power_on(info);
@@ -1060,54 +1137,28 @@ static int max77665_f_power(struct max77665_f_info *info, int pwr)
dev_err(info->dev, "%s error\n", __func__);
pwr = NVC_PWR_ERR;
}
- info->pwr_dev = pwr;
+ info->pwr_state = pwr;
if (err > 0)
return 0;
return err;
}
-static int max77665_f_power_sync(struct max77665_f_info *info, int pwr)
-{
- int err1 = 0;
- int err2 = 0;
-
- if ((info->s_mode == NVC_SYNC_OFF) ||
- (info->s_mode == NVC_SYNC_MASTER) ||
- (info->s_mode == NVC_SYNC_STEREO))
- err1 = max77665_f_power(info, pwr);
- if ((info->s_mode == NVC_SYNC_SLAVE) ||
- (info->s_mode == NVC_SYNC_STEREO))
- err2 = max77665_f_power(info->s_info, pwr);
- return err1 | err2;
-}
-
-static int max77665_f_power_user_set(struct max77665_f_info *info, int pwr)
+static inline int max77665_f_power_user_set(
+ struct max77665_f_info *info, int pwr)
{
int err = 0;
if (!pwr || (pwr > NVC_PWR_ON))
return 0;
- if (pwr > info->pwr_dev)
- err = max77665_f_power_sync(info, pwr);
- if (!err)
- info->pwr_api = pwr;
- else
- info->pwr_api = NVC_PWR_ERR;
+ err = max77665_f_power_set(info, pwr);
if (info->pdata->cfg & NVC_CFG_NOERR)
return 0;
return err;
}
-static int max77665_f_dev_power_set(struct max77665_f_info *info, int pwr)
-{
- if (pwr < info->pwr_api)
- pwr = info->pwr_api;
- return max77665_f_power(info, pwr);
-}
-
static int max77665_f_get_param(struct max77665_f_info *info, long arg)
{
struct nvc_param params;
@@ -1116,43 +1167,70 @@ static int max77665_f_get_param(struct max77665_f_info *info, long arg)
u32 data_size = 0;
u8 reg;
- if (copy_from_user(&params,
- (const void __user *)arg,
+ if (copy_from_user(&params, (const void __user *)arg,
sizeof(struct nvc_param))) {
dev_err(info->dev, "%s %d copy_from_user err\n",
__func__, __LINE__);
return -EINVAL;
}
- if (info->s_mode == NVC_SYNC_SLAVE)
- info = info->s_info;
switch (params.param) {
- case NVC_PARAM_FLASH_CAPS:
- dev_dbg(info->dev, "%s FLASH_CAPS\n", __func__);
- data_ptr = info->flash_cap;
+ case NVC_PARAM_TORCH_QUERY:
+ dev_dbg(info->dev, "%s QUERY\n", __func__);
+ data_ptr = &info->query;
+ data_size = sizeof(info->query);
+ break;
+ case NVC_PARAM_FLASH_EXT_CAPS:
+ dev_dbg(info->dev, "%s EXT_FLASH_CAPS %d\n",
+ __func__, params.variant);
+ if (params.variant >= info->query.flash_num) {
+ dev_err(info->dev, "%s unsupported flash index.\n",
+ __func__);
+ return -EINVAL;
+ }
+ data_ptr = info->flash_cap[params.variant];
data_size = info->flash_cap_size;
break;
-
+ case NVC_PARAM_TORCH_EXT_CAPS:
+ dev_dbg(info->dev, "%s EXT_TORCH_CAPS %d\n",
+ __func__, params.variant);
+ if (params.variant >= info->query.torch_num) {
+ dev_err(info->dev, "%s unsupported torch index.\n",
+ __func__);
+ return -EINVAL;
+ }
+ data_ptr = info->torch_cap[params.variant];
+ data_size = info->torch_cap_size;
+ break;
case NVC_PARAM_FLASH_LEVEL:
- reg = info->regs.led1_curr;
- data_ptr = &info->flash_cap->levels[reg].guidenum;
- data_size = sizeof(info->flash_cap->levels[reg].guidenum);
+ if (params.variant >= info->query.flash_num) {
+ dev_err(info->dev,
+ "%s unsupported flash index.\n", __func__);
+ return -EINVAL;
+ }
+ if (params.variant > 0)
+ reg = info->regs.led2_curr;
+ else
+ reg = info->regs.led1_curr;
+ data_ptr = &reg;
+ data_size = sizeof(reg);
dev_dbg(info->dev, "%s FLASH_LEVEL %d\n", __func__, reg);
break;
-
- case NVC_PARAM_TORCH_CAPS:
- dev_dbg(info->dev, "%s TORCH_CAPS\n", __func__);
- data_ptr = info->torch_cap;
- data_size = info->torch_cap_size;
- break;
-
case NVC_PARAM_TORCH_LEVEL:
- reg = info->regs.led1_curr;
- data_ptr = &info->torch_cap->guidenum[reg];
- data_size = sizeof(info->torch_cap->guidenum[reg]);
+ reg = info->regs.led_tcurr;
+ if (params.variant >= info->query.torch_num) {
+ dev_err(info->dev, "%s unsupported torch index.\n",
+ __func__);
+ return -EINVAL;
+ }
+ if (params.variant > 0)
+ reg >>= 4;
+ else
+ reg &= 0x0F;
+ data_ptr = &reg;
+ data_size = sizeof(reg);
dev_dbg(info->dev, "%s TORCH_LEVEL %d\n", __func__, reg);
break;
-
case NVC_PARAM_FLASH_PIN_STATE:
pinstate = info->pdata->pinstate;
if (info->op_mode != MAXFLASH_MODE_FLASH)
@@ -1164,28 +1242,21 @@ static int max77665_f_get_param(struct max77665_f_info *info, long arg)
data_ptr = &pinstate;
data_size = sizeof(pinstate);
break;
-
- case NVC_PARAM_STEREO:
- dev_dbg(info->dev, "%s STEREO: %d\n", __func__, info->s_mode);
- data_ptr = &info->s_mode;
- data_size = sizeof(info->s_mode);
- break;
-
default:
dev_err(info->dev, "%s unsupported parameter: %d\n",
__func__, params.param);
return -EINVAL;
}
+ dev_dbg(info->dev, "%s data size user %d vs local %d\n",
+ __func__, params.sizeofvalue, data_size);
if (params.sizeofvalue < data_size) {
- dev_err(info->dev, "%s data size mismatch %d != %d\n",
- __func__, params.sizeofvalue, data_size);
+ dev_err(info->dev, "%s data size mismatch\n", __func__);
return -EINVAL;
}
if (copy_to_user((void __user *)params.p_value,
- data_ptr,
- data_size)) {
+ data_ptr, data_size)) {
dev_err(info->dev, "%s copy_to_user err line %d\n",
__func__, __LINE__);
return -EFAULT;
@@ -1194,160 +1265,118 @@ static int max77665_f_get_param(struct max77665_f_info *info, long arg)
return 0;
}
-static int max77665_f_param_update(struct max77665_f_info *info,
+static int max77665_f_get_levels(struct max77665_f_info *info,
struct nvc_param *params,
- u8 val)
+ bool flash_mode,
+ struct nvc_torch_set_level_v1 *plevels)
{
- int err;
-
- switch (params->param) {
- case NVC_PARAM_FLASH_LEVEL:
- dev_dbg(info->dev, "%s FLASH_LEVEL: %d\n", __func__, val);
- if (val) {
- info->new_ftimer = DEFAULT_FLASH_TMR_DUR;
- info->op_mode = MAXFLASH_MODE_FLASH;
- val--;
- } else
- info->op_mode = MAXFLASH_MODE_NONE;
+ struct nvc_torch_timer_capabilities_v1 *p_tm;
+ u8 op_mode;
- max77665_f_dev_power_set(info, NVC_PWR_ON);
- err = max77665_f_set_leds(info,
- info->config.led_mask, val, val);
- /*turn pwr off if no flash && no pwr_api*/
- if (info->op_mode == MAXFLASH_MODE_NONE)
- max77665_f_dev_power_set(info, NVC_PWR_OFF);
- return err;
+ if (copy_from_user(plevels, (const void __user *)params->p_value,
+ sizeof(*plevels))) {
+ dev_err(info->dev, "%s %d copy_from_user err\n",
+ __func__, __LINE__);
+ return -EINVAL;
+ }
- case NVC_PARAM_TORCH_LEVEL:
- dev_dbg(info->dev, "%s TORCH_LEVEL: %d\n", __func__, val);
- if (val) {
- info->op_mode = MAXFLASH_MODE_TORCH;
- val--;
- } else
- info->op_mode = MAXFLASH_MODE_NONE;
+ if (flash_mode) {
+ dev_dbg(info->dev, "%s FLASH_LEVEL: %d %d %d\n",
+ __func__, plevels->ledmask,
+ plevels->levels[0], plevels->levels[1]);
+ p_tm = info->flash_timeouts[0];
+ op_mode = MAXFLASH_MODE_FLASH;
+ } else {
+ dev_dbg(info->dev, "%s TORCH_LEVEL: %d %d %d\n",
+ __func__, plevels->ledmask,
+ plevels->levels[0], plevels->levels[1]);
+ p_tm = info->torch_timeouts[0];
+ op_mode = MAXFLASH_MODE_TORCH;
+ }
- max77665_f_dev_power_set(info, NVC_PWR_ON);
- err = max77665_f_set_leds(info,
- info->config.led_mask, val, val);
- /*turn pwr off if no flash && no pwr_api*/
- if (info->op_mode == MAXFLASH_MODE_NONE)
- max77665_f_dev_power_set(info, NVC_PWR_OFF);
- return err;
+ if (plevels->timeout) {
+ u16 i;
+ for (i = 0; i < p_tm->timeout_num; i++) {
+ plevels->timeout = i;
+ if (plevels->timeout == p_tm->timeouts[i].timeout)
+ break;
+ }
+ } else
+ plevels->timeout = p_tm->timeout_num - 1;
- case NVC_PARAM_FLASH_PIN_STATE:
- dev_dbg(info->dev, "%s FLASH_PIN_STATE: %d\n",
- __func__, val);
- return max77665_f_strobe(info, val);
+ if (plevels->levels[0] == MAX77665_F_LEVEL_OFF)
+ plevels->ledmask &= ~1;
+ if (plevels->levels[1] == MAX77665_F_LEVEL_OFF)
+ plevels->ledmask &= ~2;
+ plevels->ledmask &= info->config.led_mask;
- default:
- dev_err(info->dev, "%s unsupported parameter: %d\n",
- __func__, params->param);
- return -EINVAL;
+ if (!plevels->ledmask)
+ info->op_mode = MAXFLASH_MODE_NONE;
+ else {
+ info->op_mode = op_mode;
+ if (info->config.synchronized_led) {
+ plevels->ledmask = 3;
+ plevels->levels[1] = plevels->levels[0];
+ }
}
+
+ dev_dbg(info->dev, "Return: %d - %d %d %d\n", info->op_mode,
+ plevels->ledmask, plevels->levels[0], plevels->levels[1]);
+ return 0;
}
static int max77665_f_set_param(struct max77665_f_info *info, long arg)
{
struct nvc_param params;
+ struct nvc_torch_set_level_v1 led_levels;
+ u8 curr1;
+ u8 curr2;
u8 val;
int err = 0;
- if (copy_from_user(&params,
- (const void __user *)arg,
- sizeof(struct nvc_param))) {
- dev_err(info->dev, "%s %d copy_from_user err\n",
- __func__, __LINE__);
- return -EINVAL;
- }
-
- if (copy_from_user(&val, (const void __user *)params.p_value,
- sizeof(val))) {
+ if (copy_from_user(
+ &params, (const void __user *)arg, sizeof(struct nvc_param))) {
dev_err(info->dev, "%s %d copy_from_user err\n",
__func__, __LINE__);
return -EINVAL;
}
- /* parameters independent of sync mode */
switch (params.param) {
- case NVC_PARAM_STEREO:
- dev_dbg(info->dev, "%s STEREO: %d\n", __func__, (int)val);
- if (val == info->s_mode)
- return 0;
-
- switch (val) {
- case NVC_SYNC_OFF:
- info->s_mode = val;
- if (info->s_info != NULL) {
- info->s_info->s_mode = val;
- max77665_f_power(info->s_info, NVC_PWR_OFF);
- }
- break;
-
- case NVC_SYNC_MASTER:
- info->s_mode = val;
- if (info->s_info != NULL)
- info->s_info->s_mode = val;
- break;
-
- case NVC_SYNC_SLAVE:
- case NVC_SYNC_STEREO:
- if (info->s_info != NULL) {
- /* sync power */
- info->s_info->pwr_api = info->pwr_api;
- err = max77665_f_power(info->s_info,
- info->pwr_dev);
- if (!err) {
- info->s_mode = val;
- info->s_info->s_mode = val;
- } else {
- max77665_f_power(info->s_info,
- NVC_PWR_OFF);
- err = -EIO;
- }
- } else {
- err = -EINVAL;
- }
- break;
-
- default:
- err = -EINVAL;
- }
- if (info->pdata->cfg & NVC_CFG_NOERR)
- return 0;
-
+ case NVC_PARAM_FLASH_LEVEL:
+ max77665_f_get_levels(info, &params, true, &led_levels);
+ info->new_ftimer = led_levels.timeout & 0X0F;
+ curr1 = led_levels.levels[0];
+ curr2 = led_levels.levels[1];
+ err = max77665_f_set_leds(info,
+ led_levels.ledmask, curr1, curr2);
return err;
-
- default:
- /* parameters dependent on sync mode */
- switch (info->s_mode) {
- case NVC_SYNC_OFF:
- case NVC_SYNC_MASTER:
- return max77665_f_param_update(info, &params, val);
-
- case NVC_SYNC_SLAVE:
- return max77665_f_param_update(info->s_info,
- &params,
- val);
-
- case NVC_SYNC_STEREO:
- err = max77665_f_param_update(info, &params, val);
- if (!(info->pdata->cfg & NVC_CFG_SYNC_I2C_MUX))
- err |= max77665_f_param_update(info->s_info,
- &params,
- val);
- return err;
-
- default:
- dev_err(info->dev, "%s %d internal err\n",
- __func__, __LINE__);
+ case NVC_PARAM_TORCH_LEVEL:
+ max77665_f_get_levels(info, &params, false, &led_levels);
+ info->new_ftimer = led_levels.timeout & 0X0F;
+ curr1 = led_levels.levels[0];
+ curr2 = led_levels.levels[1];
+ err = max77665_f_set_leds(info,
+ led_levels.ledmask, curr1, curr2);
+ return err;
+ case NVC_PARAM_FLASH_PIN_STATE:
+ if (copy_from_user(&val, (const void __user *)params.p_value,
+ sizeof(val))) {
+ dev_err(info->dev, "%s %d copy_from_user err\n",
+ __func__, __LINE__);
return -EINVAL;
}
+ dev_dbg(info->dev, "%s FLASH_PIN_STATE: %d\n",
+ __func__, val);
+ return max77665_f_strobe(info, val);
+ default:
+ dev_err(info->dev, "%s unsupported parameter: %d\n",
+ __func__, params.param);
+ return -EINVAL;
}
}
-static long max77665_f_ioctl(struct file *file,
- unsigned int cmd,
- unsigned long arg)
+static long max77665_f_ioctl(
+ struct file *file, unsigned int cmd, unsigned long arg)
{
struct max77665_f_info *info = file->private_data;
int pwr;
@@ -1355,31 +1384,24 @@ static long max77665_f_ioctl(struct file *file,
switch (cmd) {
case NVC_IOCTL_PARAM_WR:
return max77665_f_set_param(info, arg);
-
case NVC_IOCTL_PARAM_RD:
return max77665_f_get_param(info, arg);
-
case NVC_IOCTL_PWR_WR:
/* This is a Guaranteed Level of Service (GLOS) call */
pwr = (int)arg * 2;
dev_dbg(info->dev, "%s PWR_WR: %d\n", __func__, pwr);
return max77665_f_power_user_set(info, pwr);
-
case NVC_IOCTL_PWR_RD:
- if (info->s_mode == NVC_SYNC_SLAVE)
- pwr = info->s_info->pwr_api / 2;
- else
- pwr = info->pwr_api / 2;
+ pwr = info->pwr_state / 2;
dev_dbg(info->dev, "%s PWR_RD: %d\n", __func__, pwr);
- if (copy_to_user((void __user *)arg, (const void *)&pwr,
- sizeof(pwr))) {
+ if (copy_to_user(
+ (void __user *)arg, (const void *)&pwr, sizeof(pwr))) {
dev_err(info->dev, "%s copy_to_user err line %d\n",
__func__, __LINE__);
return -EFAULT;
}
return 0;
-
default:
dev_err(info->dev, "%s unsupported ioctl: %x\n",
__func__, cmd);
@@ -1387,88 +1409,18 @@ static long max77665_f_ioctl(struct file *file,
}
}
-static int max77665_f_sync_enable(int dev1, int dev2)
-{
- struct max77665_f_info *sync1 = NULL;
- struct max77665_f_info *sync2 = NULL;
- struct max77665_f_info *pos = NULL;
-
- rcu_read_lock();
- list_for_each_entry_rcu(pos, &max77665_f_info_list, list) {
- if (pos->pdata->num == dev1) {
- sync1 = pos;
- break;
- }
- }
- pos = NULL;
- list_for_each_entry_rcu(pos, &max77665_f_info_list, list) {
- if (pos->pdata->num == dev2) {
- sync2 = pos;
- break;
- }
- }
- rcu_read_unlock();
- if (sync1 != NULL)
- sync1->s_info = NULL;
- if (sync2 != NULL)
- sync2->s_info = NULL;
- if (!dev1 && !dev2)
- return 0; /* no err if default instance 0's used */
-
- if (dev1 == dev2)
- return -EINVAL; /* err if sync instance is itself */
-
- if ((sync1 != NULL) && (sync2 != NULL)) {
- sync1->s_info = sync2;
- sync2->s_info = sync1;
- }
-
- return 0;
-}
-
-static int max77665_f_sync_disable(struct max77665_f_info *info)
-{
- if (info->s_info != NULL) {
- info->s_info->s_mode = 0;
- info->s_info->s_info = NULL;
- info->s_mode = 0;
- info->s_info = NULL;
- return 0;
- }
-
- return -EINVAL;
-}
-
static int max77665_f_open(struct inode *inode, struct file *file)
{
- struct max77665_f_info *info = NULL;
- struct max77665_f_info *pos = NULL;
- int err;
+ struct miscdevice *miscdev = file->private_data;
+ struct max77665_f_info *info;
- rcu_read_lock();
- list_for_each_entry_rcu(pos, &max77665_f_info_list, list) {
- if (pos->miscdev.minor == iminor(inode)) {
- info = pos;
- break;
- }
- }
- rcu_read_unlock();
+ info = container_of(miscdev, struct max77665_f_info, miscdev);
if (!info)
return -ENODEV;
- err = max77665_f_sync_enable(info->pdata->num, info->pdata->sync);
- if (err == -EINVAL)
- dev_err(info->dev,
- "%s err: invalid num (%u) and sync (%u) instance\n",
- __func__, info->pdata->num, info->pdata->sync);
if (atomic_xchg(&info->in_use, 1))
return -EBUSY;
- if (info->s_info != NULL) {
- if (atomic_xchg(&info->s_info->in_use, 1))
- return -EBUSY;
- }
-
file->private_data = info;
dev_dbg(info->dev, "%s\n", __func__);
return 0;
@@ -1479,12 +1431,9 @@ static int max77665_f_release(struct inode *inode, struct file *file)
struct max77665_f_info *info = file->private_data;
dev_dbg(info->dev, "%s\n", __func__);
- max77665_f_power_sync(info, NVC_PWR_OFF);
+ max77665_f_power_set(info, NVC_PWR_OFF);
file->private_data = NULL;
WARN_ON(!atomic_xchg(&info->in_use, 0));
- if (info->s_info != NULL)
- WARN_ON(!atomic_xchg(&info->s_info->in_use, 0));
- max77665_f_sync_disable(info);
return 0;
}
@@ -1546,13 +1495,8 @@ static const struct file_operations max77665_f_fileops = {
static void max77665_f_del(struct max77665_f_info *info)
{
- max77665_f_power_sync(info, NVC_PWR_OFF);
+ max77665_f_power_set(info, NVC_PWR_OFF);
max77665_f_power_put(&info->pwr_rail);
- max77665_f_sync_disable(info);
- spin_lock(&max77665_f_spinlock);
- list_del_rcu(&info->list);
- spin_unlock(&max77665_f_spinlock);
- synchronize_rcu();
}
static int max77665_f_remove(struct platform_device *pdev)
@@ -1570,6 +1514,38 @@ static int max77665_f_remove(struct platform_device *pdev)
static int max77665_f_debugfs_init(struct max77665_f_info *info);
+static void max77665_f_caps_layout(struct max77665_f_info *info)
+{
+#define MAX77665_FLASH_CAP_TIMEOUT_SIZE \
+ (max77665_f_flash_cap_size + max77665_f_flash_timeout_size)
+#define MAX77665_TORCH_CAP_TIMEOUT_SIZE \
+ (max77665_f_torch_cap_size + max77665_f_torch_timeout_size)
+ void *start_ptr = (void *)info + sizeof(*info);
+
+ info->flash_cap[0] = start_ptr;
+ info->flash_timeouts[0] = start_ptr + max77665_f_flash_cap_size;
+
+ start_ptr += MAX77665_FLASH_CAP_TIMEOUT_SIZE;
+ info->flash_cap[1] = start_ptr;
+ info->flash_timeouts[1] = start_ptr + max77665_f_flash_cap_size;
+
+ info->flash_cap_size = MAX77665_FLASH_CAP_TIMEOUT_SIZE;
+
+ start_ptr += MAX77665_FLASH_CAP_TIMEOUT_SIZE;
+ info->torch_cap[0] = start_ptr;
+ info->torch_timeouts[0] = start_ptr + max77665_f_torch_cap_size;
+
+ start_ptr += MAX77665_TORCH_CAP_TIMEOUT_SIZE;
+ info->torch_cap[1] = start_ptr;
+ info->torch_timeouts[1] = start_ptr + max77665_f_torch_cap_size;
+
+ info->torch_cap_size = MAX77665_TORCH_CAP_TIMEOUT_SIZE;
+ dev_dbg(info->dev, "%s: %d(%d + %d), %d(%d + %d)\n", __func__,
+ info->flash_cap_size, max77665_f_flash_cap_size,
+ max77665_f_flash_timeout_size, info->torch_cap_size,
+ max77665_f_torch_cap_size, max77665_f_torch_timeout_size);
+}
+
static int max77665_f_probe(struct platform_device *pdev)
{
struct max77665_f_info *info;
@@ -1603,10 +1579,7 @@ static int max77665_f_probe(struct platform_device *pdev)
} else
dev_warn(&pdev->dev, "%s NO platform data\n", __func__);
- info->flash_cap = (void *)info + sizeof(*info);
- info->torch_cap = (void *)info->flash_cap +
- max77665_f_max_flash_cap_size;
- info->sustainTime = SUSTAINTIME_DEF;
+ max77665_f_caps_layout(info);
max77665_f_update_config(info);
@@ -1619,10 +1592,6 @@ static int max77665_f_probe(struct platform_device *pdev)
dev_set_drvdata(info->dev, info);
mutex_init(&info->mutex);
- INIT_LIST_HEAD(&info->list);
- spin_lock(&max77665_f_spinlock);
- list_add_rcu(&info->list, &max77665_f_info_list);
- spin_unlock(&max77665_f_spinlock);
if (info->pdata->dev_name != NULL)
strcpy(dname, info->pdata->dev_name);
@@ -1664,7 +1633,7 @@ static int max77665_f_status_show(struct seq_file *s, void *data)
" PinState Values = 0x%04x\n"
" Max_Peak_Current = %dmA\n"
,
- info->pwr_dev,
+ info->pwr_state,
info->config.led_mask,
info->regs.led1_curr,
info->regs.led2_curr,
@@ -1732,9 +1701,9 @@ set_attr:
break;
case 'p':
if (val)
- max77665_f_power(info, NVC_PWR_ON);
+ max77665_f_power_set(info, NVC_PWR_ON);
else
- max77665_f_power(info, NVC_PWR_OFF);
+ max77665_f_power_set(info, NVC_PWR_OFF);
break;
case 'k':
if (val & 0xffff)
diff --git a/drivers/media/video/tegra/ov5693.c b/drivers/media/video/tegra/ov5693.c
index f63d5ef365da..8c8797f9a871 100644
--- a/drivers/media/video/tegra/ov5693.c
+++ b/drivers/media/video/tegra/ov5693.c
@@ -110,8 +110,9 @@ static struct nvc_imager_static_nvc ov5693_dflt_sdata = {
.res_chg_wait_time = OV5693_RES_CHG_WAIT_TIME_MS,
};
-static const struct ov5693_reg ov5693_2592x1944_i2c[] = {
+static const struct ov5693_reg ov5693_2592x1944_hdr_i2c[] = {
{OV5693_TABLE_RESET, 0},/* Including sw reset */
+
{0x3001, 0x0a},
{0x3002, 0x80},
{0x3006, 0x00},
@@ -128,10 +129,6 @@ static const struct ov5693_reg ov5693_2592x1944_i2c[] = {
{0x3021, 0x00},
{0x3022, 0x01},
{0x3028, 0x44},
- {0x3090, 0x02},
- {0x3091, 0x0e},
- {0x3092, 0x00},
- {0x3093, 0x00},
{0x3098, 0x03},
{0x3099, 0x1e},
{0x309a, 0x02},
@@ -154,19 +151,19 @@ static const struct ov5693_reg ov5693_2592x1944_i2c[] = {
{0x3405, 0x00},
{0x3406, 0x01},
{0x3500, 0x00},
- {0x3501, 0x7b},
- {0x3502, 0x00},
+ {0x3501, 0x9a},
+ {0x3502, 0x80},
{0x3503, 0x07},
{0x3504, 0x00},
{0x3505, 0x00},
{0x3506, 0x00},
- {0x3507, 0x02},
- {0x3508, 0x00},
- {0x3509, 0x08},
+ {0x3507, 0x01},
+ {0x3508, 0x80},
+ {0x3509, 0x10},
{0x350a, 0x00},
{0x350b, 0x40},
{0x3601, 0x0a},
- {0x3602, 0x18},
+ {0x3602, 0x38},
{0x3612, 0x80},
{0x3620, 0x54},
{0x3621, 0xc7},
@@ -209,6 +206,7 @@ static const struct ov5693_reg ov5693_2592x1944_i2c[] = {
{0x371e, 0xa1},
{0x371f, 0x0c},
{0x3721, 0x00},
+ {0x3724, 0x10},
{0x3726, 0x00},
{0x372a, 0x01},
{0x3730, 0x10},
@@ -235,6 +233,7 @@ static const struct ov5693_reg ov5693_2592x1944_i2c[] = {
{0x3759, 0x0f},
{0x376b, 0x44},
{0x375c, 0x04},
+ {0x3774, 0x10},
{0x3776, 0x00},
{0x377f, 0x08},
{0x3780, 0x22},
@@ -271,10 +270,10 @@ static const struct ov5693_reg ov5693_2592x1944_i2c[] = {
{0x3809, 0x20},
{0x380a, 0x07},
{0x380b, 0x98},
- {0x380c, 0x0a},
- {0x380d, 0x80},
- {0x380e, 0x07},
- {0x380f, 0xc0},
+ {0x380c, 0x0e},
+ {0x380d, 0x40},
+ {0x380e, 0x09},
+ {0x380f, 0xb4},
{0x3810, 0x00},
{0x3811, 0x02},
{0x3812, 0x00},
@@ -282,15 +281,15 @@ static const struct ov5693_reg ov5693_2592x1944_i2c[] = {
{0x3814, 0x11},
{0x3815, 0x11},
{0x3820, 0x00},
- {0x3821, 0x1e},
+ {0x3821, 0x9e},
{0x3823, 0x00},
{0x3824, 0x00},
{0x3825, 0x00},
{0x3826, 0x00},
{0x3827, 0x00},
{0x382a, 0x04},
- {0x3a04, 0x06},
- {0x3a05, 0x14},
+ {0x3a04, 0x09},
+ {0x3a05, 0xa9},
{0x3a06, 0x00},
{0x3a07, 0xfe},
{0x3b00, 0x00},
@@ -298,25 +297,6 @@ static const struct ov5693_reg ov5693_2592x1944_i2c[] = {
{0x3b03, 0x00},
{0x3b04, 0x00},
{0x3b05, 0x00},
- {0x3d00, 0x00},
- {0x3d01, 0x00},
- {0x3d02, 0x00},
- {0x3d03, 0x00},
- {0x3d04, 0x00},
- {0x3d05, 0x00},
- {0x3d06, 0x00},
- {0x3d07, 0x00},
- {0x3d08, 0x00},
- {0x3d09, 0x00},
- {0x3d0a, 0x00},
- {0x3d0b, 0x00},
- {0x3d0c, 0x00},
- {0x3d0d, 0x00},
- {0x3d0e, 0x00},
- {0x3d0f, 0x00},
- {0x3d80, 0x00},
- {0x3d81, 0x00},
- {0x3d84, 0x00},
{0x3e07, 0x20},
{0x4000, 0x08},
{0x4001, 0x04},
@@ -325,10 +305,13 @@ static const struct ov5693_reg ov5693_2592x1944_i2c[] = {
{0x4005, 0x18},
{0x4006, 0x20},
{0x4008, 0x24},
- {0x4009, 0x10},
+ {0x4009, 0x40},
{0x400c, 0x00},
{0x400d, 0x00},
{0x4058, 0x00},
+ {0x404e, 0x37},
+ {0x404f, 0x8f},
+ {0x4058, 0x00},
{0x4101, 0xb2},
{0x4303, 0x00},
{0x4304, 0x08},
@@ -382,9 +365,9 @@ static const struct ov5693_reg ov5693_2592x1944_i2c[] = {
{OV5693_TABLE_END, 0x0000}
};
-static const struct ov5693_reg ov5693_1296x972_i2c[] = {
+static const struct ov5693_reg ov5693_1296x972_hdr_i2c[] = {
{OV5693_TABLE_RESET, 0},/* Including sw reset */
- {0x0103, 0x01},
+
{0x3001, 0x0a},
{0x3002, 0x80},
{0x3006, 0x00},
@@ -423,15 +406,15 @@ static const struct ov5693_reg ov5693_1296x972_i2c[] = {
{0x3405, 0x00},
{0x3406, 0x01},
{0x3500, 0x00},
- {0x3501, 0x7b},
+ {0x3501, 0x72},
{0x3502, 0x00},
{0x3503, 0x07},
{0x3504, 0x00},
{0x3505, 0x00},
{0x3506, 0x00},
- {0x3507, 0x02},
- {0x3508, 0x00},
- {0x3509, 0x08},
+ {0x3507, 0x01},
+ {0x3508, 0x80},
+ {0x3509, 0x10},
{0x350a, 0x00},
{0x350b, 0x40},
{0x3601, 0x0a},
@@ -463,7 +446,7 @@ static const struct ov5693_reg ov5693_1296x972_i2c[] = {
{0x3703, 0xd8},
{0x3704, 0x78},
{0x3705, 0x02},
- {0x3708, 0xe6},
+ {0x3708, 0xe2},
{0x3709, 0xc3},
{0x370a, 0x00},
{0x370b, 0x20},
@@ -530,38 +513,38 @@ static const struct ov5693_reg ov5693_1296x972_i2c[] = {
{0x37cb, 0x00},
{0x37de, 0x00},
{0x37df, 0x00},
- {0x3800, 0x00},
- {0x3801, 0x00},
- {0x3802, 0x00},
- {0x3803, 0x00},
- {0x3804, 0x0a},
- {0x3805, 0x3f},
- {0x3806, 0x07},
- {0x3807, 0xa3},
+ {0x3800, 0x02},
+ {0x3801, 0xa0},
+ {0x3802, 0x01},
+ {0x3803, 0xe8},
+ {0x3804, 0x07},
+ {0x3805, 0xb7},
+ {0x3806, 0x05},
+ {0x3807, 0xb9},
{0x3808, 0x05},
{0x3809, 0x10},
{0x380a, 0x03},
{0x380b, 0xcc},
- {0x380c, 0x0a},
- {0x380d, 0x80},
+ {0x380c, 0x0b},
+ {0x380d, 0x40},
{0x380e, 0x07},
- {0x380f, 0xc0},
+ {0x380f, 0x3a},
{0x3810, 0x00},
{0x3811, 0x02},
{0x3812, 0x00},
{0x3813, 0x02},
- {0x3814, 0x31},
- {0x3815, 0x31},
- {0x3820, 0x01},
- {0x3821, 0x1f},
+ {0x3814, 0x11},
+ {0x3815, 0x11},
+ {0x3820, 0x00},
+ {0x3821, 0x9e},
{0x3823, 0x00},
{0x3824, 0x00},
{0x3825, 0x00},
{0x3826, 0x00},
{0x3827, 0x00},
{0x382a, 0x04},
- {0x3a04, 0x06},
- {0x3a05, 0x14},
+ {0x3a04, 0x09},
+ {0x3a05, 0xa9},
{0x3a06, 0x00},
{0x3a07, 0xfe},
{0x3b00, 0x00},
@@ -633,11 +616,13 @@ static const struct ov5693_reg ov5693_1296x972_i2c[] = {
{0x5e00, 0x00},
{0x5e10, 0x0c},
{0x0100, 0x01},
+
{OV5693_TABLE_END, 0x0000}
};
-static const struct ov5693_reg ov5693_1920x1080_i2c[] = {
+static const struct ov5693_reg ov5693_1920x1080_hdr_i2c[] = {
{OV5693_TABLE_RESET, 0x0},/*, 0xIncluding, 0xsw, 0xreset, 0x*/
+
{0x3001, 0x0a},
{0x3002, 0x80},
{0x3006, 0x00},
@@ -676,15 +661,15 @@ static const struct ov5693_reg ov5693_1920x1080_i2c[] = {
{0x3405, 0x00},
{0x3406, 0x01},
{0x3500, 0x00},
- {0x3501, 0x7b},
+ {0x3501, 0x72},
{0x3502, 0x00},
{0x3503, 0x07},
{0x3504, 0x00},
{0x3505, 0x00},
{0x3506, 0x00},
- {0x3507, 0x02},
- {0x3508, 0x00},
- {0x3509, 0x08},
+ {0x3507, 0x01},
+ {0x3508, 0x80},
+ {0x3509, 0x10},
{0x350a, 0x00},
{0x350b, 0x40},
{0x3601, 0x0a},
@@ -783,22 +768,22 @@ static const struct ov5693_reg ov5693_1920x1080_i2c[] = {
{0x37cb, 0x00},
{0x37de, 0x00},
{0x37df, 0x00},
- {0x3800, 0x00},
- {0x3801, 0x00},
- {0x3802, 0x00},
- {0x3803, 0xf8},
- {0x3804, 0x0a},
- {0x3805, 0x3f},
- {0x3806, 0x06},
- {0x3807, 0xab},
+ {0x3800, 0x01},
+ {0x3801, 0x70},
+ {0x3802, 0x01},
+ {0x3803, 0xbc},
+ {0x3804, 0x09},
+ {0x3805, 0x0f},
+ {0x3806, 0x05},
+ {0x3807, 0xff},
{0x3808, 0x07},
{0x3809, 0x80},
{0x380a, 0x04},
{0x380b, 0x38},
- {0x380c, 0x0a},
- {0x380d, 0x80},
+ {0x380c, 0x0b},
+ {0x380d, 0x40},
{0x380e, 0x07},
- {0x380f, 0xc0},
+ {0x380f, 0x3a},
{0x3810, 0x00},
{0x3811, 0x02},
{0x3812, 0x00},
@@ -806,15 +791,15 @@ static const struct ov5693_reg ov5693_1920x1080_i2c[] = {
{0x3814, 0x11},
{0x3815, 0x11},
{0x3820, 0x00},
- {0x3821, 0x1e},
+ {0x3821, 0x9e},
{0x3823, 0x00},
{0x3824, 0x00},
{0x3825, 0x00},
{0x3826, 0x00},
{0x3827, 0x00},
{0x382a, 0x04},
- {0x3a04, 0x06},
- {0x3a05, 0x14},
+ {0x3a04, 0x09},
+ {0x3a05, 0xa9},
{0x3a06, 0x00},
{0x3a07, 0xfe},
{0x3b00, 0x00},
@@ -859,7 +844,7 @@ static const struct ov5693_reg ov5693_1920x1080_i2c[] = {
{0x4837, 0x0a},
{0x5000, 0x06},
{0x5001, 0x01},
- {0x5002, 0x80},
+ {0x5002, 0x00},
{0x5003, 0x20},
{0x5046, 0x0a},
{0x5013, 0x00},
@@ -890,8 +875,9 @@ static const struct ov5693_reg ov5693_1920x1080_i2c[] = {
};
-static const struct ov5693_reg ov5693_1280x720_120fps_i2c[] = {
+static const struct ov5693_reg ov5693_1280x720_hdr_i2c[] = {
{OV5693_TABLE_RESET, 0},/* Including sw reset */
+
{0x3001, 0x0a},
{0x3002, 0x80},
{0x3006, 0x00},
@@ -930,15 +916,15 @@ static const struct ov5693_reg ov5693_1280x720_120fps_i2c[] = {
{0x3405, 0x00},
{0x3406, 0x01},
{0x3500, 0x00},
- {0x3501, 0x2e},
- {0x3502, 0x80},
+ {0x3501, 0x39},
+ {0x3502, 0x00},
{0x3503, 0x07},
{0x3504, 0x00},
{0x3505, 0x00},
{0x3506, 0x00},
- {0x3507, 0x02},
- {0x3508, 0x00},
- {0x3509, 0x08},
+ {0x3507, 0x01},
+ {0x3508, 0x80},
+ {0x3509, 0x10},
{0x350a, 0x00},
{0x350b, 0x40},
{0x3601, 0x0a},
@@ -970,8 +956,8 @@ static const struct ov5693_reg ov5693_1280x720_120fps_i2c[] = {
{0x3703, 0xd8},
{0x3704, 0x78},
{0x3705, 0x02},
- {0x3708, 0xe6},
- {0x3709, 0xc7},
+ {0x3708, 0xe2},
+ {0x3709, 0xc3},
{0x370a, 0x00},
{0x370b, 0x20},
{0x370c, 0x0c},
@@ -1037,38 +1023,38 @@ static const struct ov5693_reg ov5693_1280x720_120fps_i2c[] = {
{0x37cb, 0x00},
{0x37de, 0x00},
{0x37df, 0x00},
- {0x3800, 0x00},
- {0x3801, 0x00},
- {0x3802, 0x00},
- {0x3803, 0xf4},
- {0x3804, 0x0a},
- {0x3805, 0x3f},
- {0x3806, 0x06},
- {0x3807, 0xab},
+ {0x3800, 0x02},
+ {0x3801, 0xa8},
+ {0x3802, 0x02},
+ {0x3803, 0x68},
+ {0x3804, 0x07},
+ {0x3805, 0xb7},
+ {0x3806, 0x05},
+ {0x3807, 0x3b},
{0x3808, 0x05},
{0x3809, 0x00},
{0x380a, 0x02},
{0x380b, 0xd0},
- {0x380c, 0x06},
- {0x380d, 0xd8},
- {0x380e, 0x02},
- {0x380f, 0xf8},
+ {0x380c, 0x0b},
+ {0x380d, 0x40},
+ {0x380e, 0x03},
+ {0x380f, 0x9e},
{0x3810, 0x00},
{0x3811, 0x02},
{0x3812, 0x00},
{0x3813, 0x02},
- {0x3814, 0x31},
- {0x3815, 0x31},
- {0x3820, 0x04},
- {0x3821, 0x1f},
+ {0x3814, 0x11},
+ {0x3815, 0x11},
+ {0x3820, 0x00},
+ {0x3821, 0x9e},
{0x3823, 0x00},
{0x3824, 0x00},
{0x3825, 0x00},
{0x3826, 0x00},
{0x3827, 0x00},
{0x382a, 0x04},
- {0x3a04, 0x06},
- {0x3a05, 0x14},
+ {0x3a04, 0x09},
+ {0x3a05, 0xa9},
{0x3a06, 0x00},
{0x3a07, 0xfe},
{0x3b00, 0x00},
@@ -1140,22 +1126,22 @@ static const struct ov5693_reg ov5693_1280x720_120fps_i2c[] = {
{0x5e00, 0x00},
{0x5e10, 0x0c},
{0x0100, 0x01},
- {0x350b, 0xF8},
+
{OV5693_TABLE_END, 0x0000}
};
enum {
- OV5693_MODE_2592x1944 = 0,
- OV5693_MODE_1920x1080,
- OV5693_MODE_1296x972,
- OV5693_MODE_1280x720_120FPS,
+ OV5693_MODE_2592x1944_HDR = 0,
+ OV5693_MODE_1920x1080_HDR,
+ OV5693_MODE_1296x972_HDR,
+ OV5693_MODE_1280x720_HDR,
};
static const struct ov5693_reg *mode_table[] = {
- [OV5693_MODE_2592x1944] = ov5693_2592x1944_i2c,
- [OV5693_MODE_1920x1080] = ov5693_1920x1080_i2c,
- [OV5693_MODE_1296x972] = ov5693_1296x972_i2c,
- [OV5693_MODE_1280x720_120FPS] = ov5693_1280x720_120fps_i2c,
+ [OV5693_MODE_2592x1944_HDR] = ov5693_2592x1944_hdr_i2c,
+ [OV5693_MODE_1920x1080_HDR] = ov5693_1920x1080_hdr_i2c,
+ [OV5693_MODE_1296x972_HDR] = ov5693_1296x972_hdr_i2c,
+ [OV5693_MODE_1280x720_HDR] = ov5693_1280x720_hdr_i2c,
};
static int ov5693_i2c_rd8(struct ov5693_info *info, u16 reg, u8 *val)
@@ -1241,8 +1227,9 @@ static inline int ov5693_frame_length_reg(struct ov5693_reg *regs,
}
static inline int ov5693_coarse_time_reg(struct ov5693_reg *regs,
- u32 coarse_time)
+ u32 coarse_time, u32 coarse_time_short)
{
+ int ret = 0;
regs->addr = 0x3500;
regs->val = (coarse_time >> 12) & 0xff;
(regs + 1)->addr = 0x3501;
@@ -1250,7 +1237,20 @@ static inline int ov5693_coarse_time_reg(struct ov5693_reg *regs,
(regs + 2)->addr = 0x3502;
(regs + 2)->val = (coarse_time & 0xf) << 4;
- return 3;
+ ret += 3;
+
+ if (coarse_time_short != OV5693_INVALID_COARSE_TIME) {
+ regs->addr = 0x3506;
+ regs->val = (coarse_time_short >> 12) & 0xff;
+ (regs + 1)->addr = 0x3507;
+ (regs + 1)->val = (coarse_time_short >> 4) & 0xff;
+ (regs + 2)->addr = 0x3508;
+ (regs + 2)->val = (coarse_time_short & 0xf) << 4;
+
+ ret += 3;
+ }
+
+ return ret;
}
#define OV5693_ENTER_GROUP_HOLD(group_hold) \
@@ -1294,14 +1294,17 @@ static int ov5693_set_frame_length(struct ov5693_info *info,
}
static int ov5693_set_coarse_time(struct ov5693_info *info,
- u32 coarse_time, bool group_hold)
+ u32 coarse_time, u32 coarse_time_short,
+ bool group_hold)
{
struct ov5693_reg reg_list[16];
int err = 0;
int offset = 0;
OV5693_ENTER_GROUP_HOLD(group_hold);
- offset += ov5693_coarse_time_reg(reg_list + offset, coarse_time);
+ offset += ov5693_coarse_time_reg(reg_list + offset,
+ coarse_time,
+ coarse_time_short);
OV5693_LEAVE_GROUP_HOLD(group_hold);
reg_list[offset].addr = OV5693_TABLE_END;
@@ -1343,7 +1346,9 @@ static int ov5693_exposure_wr(struct ov5693_info *info,
bool group_hold = true; /* To use GROUP_HOLD macros */
OV5693_ENTER_GROUP_HOLD(group_hold);
- offset += ov5693_coarse_time_reg(reg_list + offset, mode->coarse_time);
+ offset += ov5693_coarse_time_reg(reg_list + offset,
+ mode->coarse_time,
+ mode->coarse_time_short);
offset += ov5693_gain_reg(reg_list + offset, mode->gain);
OV5693_LEAVE_GROUP_HOLD(group_hold);
@@ -1389,7 +1394,7 @@ static int ov5693_set_group_hold(struct ov5693_info *info,
ae->frame_length);
if (ae->coarse_time_enable)
offset += ov5693_coarse_time_reg(reg_list + offset,
- ae->coarse_time);
+ ae->coarse_time, OV5693_INVALID_COARSE_TIME);
OV5693_LEAVE_GROUP_HOLD(group_hold);
reg_list[offset].addr = OV5693_TABLE_END;
@@ -1406,7 +1411,7 @@ static int ov5693_gpio_rd(struct ov5693_info *info,
if (info->gpio[type].gpio) {
val = gpio_get_value_cansleep(info->gpio[type].gpio);
dev_dbg(&info->i2c_client->dev, "%s %u %d\n", __func__,
- info->gpio[type].gpio, val);
+ info->gpio[type].gpio, val);
if (!info->gpio[type].active_high)
val = !val;
val &= 1;
@@ -1427,7 +1432,7 @@ static int ov5693_gpio_wr(struct ov5693_info *info,
err = val;
gpio_set_value_cansleep(info->gpio[type].gpio, val);
dev_dbg(&info->i2c_client->dev, "%s %u %d\n", __func__,
- info->gpio[type].gpio, val);
+ info->gpio[type].gpio, val);
}
return err; /* return value written or error */
}
@@ -1712,23 +1717,19 @@ static int ov5693_set_mode(struct ov5693_info *info,
}
if (mode->res_x == 2592 && mode->res_y == 1944)
- mode_index = OV5693_MODE_2592x1944;
+ mode_index = OV5693_MODE_2592x1944_HDR;
else if (mode->res_x == 1296 && mode->res_y == 972)
- mode_index = OV5693_MODE_1296x972;
+ mode_index = OV5693_MODE_1296x972_HDR;
else if (mode->res_x == 1920 && mode->res_y == 1080)
- mode_index = OV5693_MODE_1920x1080;
+ mode_index = OV5693_MODE_1920x1080_HDR;
else if (mode->res_x == 1280 && mode->res_y == 720)
- mode_index = OV5693_MODE_1280x720_120FPS;
+ mode_index = OV5693_MODE_1280x720_HDR;
if (!info->mode_valid || (info->mode_index != mode_index))
err = ov5693_mode_wr_full(info, mode_index);
else
dev_dbg(&info->i2c_client->dev, "%s short mode\n", __func__);
- dev_dbg(&info->i2c_client->dev, "%s: mode #: %d\n",
- __func__, mode_index);
- dev_dbg(&info->i2c_client->dev, "%s: AE: %d, %d, %d\n",
- __func__, mode->frame_length,
- mode->coarse_time, mode->gain);
+
err |= ov5693_exposure_wr(info, mode);
if (err < 0) {
info->mode_valid = false;
@@ -1801,7 +1802,19 @@ static long ov5693_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return ov5693_set_frame_length(info, (u32)arg, true);
case OV5693_IOCTL_SET_COARSE_TIME:
- return ov5693_set_coarse_time(info, (u32)arg, true);
+ return ov5693_set_coarse_time(info, (u32)arg,
+ OV5693_INVALID_COARSE_TIME, true);
+
+ case OV5693_IOCTL_SET_HDR_COARSE_TIME:
+ {
+ struct ov5693_hdr *hdrcoarse = (struct ov5693_hdr *)arg;
+ int ret = ov5693_set_coarse_time(info,
+ hdrcoarse->coarse_time_long,
+ hdrcoarse->coarse_time_short,
+ false);
+ return ret;
+ }
+
case OV5693_IOCTL_SET_GAIN:
return ov5693_set_gain(info, (u32)arg, true);