]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
media: soc_camera: add imx135 sensor driver
authorBryan Wu <pengw@nvidia.com>
Tue, 19 Nov 2013 23:51:20 +0000 (15:51 -0800)
committerBryan Wu <pengw@nvidia.com>
Thu, 14 Aug 2014 20:57:53 +0000 (13:57 -0700)
Sony IMX135 camera sensor can be found on Ardbeg/Laguna. This patch
introduced sensor driver for imx135 using soc_camera interface.

Bug 1380143

Change-Id: Ifa0becf1ec2d9931ebf9ea3a4e9ea3e1013a9e36
Signed-off-by: Bryan Wu <pengw@nvidia.com>
Reviewed-on: http://git-master/r/337469
GVS: Gerrit_Virtual_Submit
Reviewed-by: Frank Chen <frankc@nvidia.com>
Reviewed-by: Matthew Pedro <mapedro@nvidia.com>
drivers/media/i2c/soc_camera/Kconfig
drivers/media/i2c/soc_camera/Makefile
drivers/media/i2c/soc_camera/imx135_v4l2.c [new file with mode: 0644]
include/media/v4l2-chip-ident.h

index 764d06c1a207b7e64fc99722b7df859928181a8b..a1b9b709f052f8db57ed4e778ab2cec3bad22cdd 100644 (file)
@@ -6,6 +6,12 @@ config SOC_CAMERA_IMX074
        help
          This driver supports IMX074 cameras from Sony
 
+config SOC_CAMERA_IMX135
+        tristate "IMX135 camera sensor support"
+       depends on SOC_CAMERA && I2C
+       help
+         This driver supports IMX135 cameras from Sony
+
 config SOC_CAMERA_MT9M001
        tristate "mt9m001 support"
        depends on SOC_CAMERA && I2C
index 63209a902b9d31fa21901b4dacfcb8edb8723328..fe0c86b92aa2a070dcb267a4882a548b137d02ed 100644 (file)
@@ -1,4 +1,5 @@
 obj-$(CONFIG_SOC_CAMERA_IMX074)                += imx074.o
+obj-$(CONFIG_SOC_CAMERA_IMX135)                += imx135_v4l2.o
 obj-$(CONFIG_SOC_CAMERA_MT9M001)       += mt9m001.o
 obj-$(CONFIG_SOC_CAMERA_MT9M111)       += mt9m111.o
 obj-$(CONFIG_SOC_CAMERA_MT9T031)       += mt9t031.o
diff --git a/drivers/media/i2c/soc_camera/imx135_v4l2.c b/drivers/media/i2c/soc_camera/imx135_v4l2.c
new file mode 100644 (file)
index 0000000..eda6453
--- /dev/null
@@ -0,0 +1,2426 @@
+/*
+ * imx135.c - imx135 sensor driver
+ *
+ * Copyright (c) 2013-2014, 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/clk.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/videodev2.h>
+
+#include <linux/kernel.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+
+#include <mach/io_dpd.h>
+
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/soc_camera.h>
+#include <media/imx135.h>
+
+#define CAM_RSTN 219   /* TEGRA_GPIO_PBB3 */
+#define CAM1_PWDN 221  /* TEGRA_GPIO_PBB5 */
+#define CAM_AF_PWDN 223        /* TEGRA_GPIO_PBB7 */
+
+static struct tegra_io_dpd csia_io = {
+       .name                   = "CSIA",
+       .io_dpd_reg_index       = 0,
+       .io_dpd_bit             = 0,
+};
+
+static struct tegra_io_dpd csib_io = {
+       .name                   = "CSIB",
+       .io_dpd_reg_index       = 0,
+       .io_dpd_bit             = 1,
+};
+
+struct imx135_reg {
+       u16 addr;
+       u8 val;
+};
+
+struct imx135_datafmt {
+       enum v4l2_mbus_pixelcode        code;
+       enum v4l2_colorspace            colorspace;
+};
+
+struct imx135 {
+       struct v4l2_subdev              subdev;
+       const struct imx135_datafmt     *fmt;
+
+       int                             mode;
+       struct imx135_power_rail        power;
+       struct imx135_sensordata        sensor_data;
+       struct i2c_client               *i2c_client;
+       struct imx135_platform_data     *pdata;
+       struct clk                      *mclk;
+       struct mutex                    imx135_camera_lock;
+       struct dentry                   *debugdir;
+};
+
+static const struct imx135_datafmt imx135_colour_fmts[] = {
+       {V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_COLORSPACE_SRGB},
+       {V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_COLORSPACE_SRGB},
+};
+
+static inline struct imx135 *to_imx135(const struct i2c_client *client)
+{
+       return container_of(i2c_get_clientdata(client), struct imx135, subdev);
+}
+
+#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
+
+#define MAX_BUFFER_SIZE 32
+#define IMX135_FRAME_LENGTH_ADDR_MSB 0x0340
+#define IMX135_FRAME_LENGTH_ADDR_LSB 0x0341
+#define IMX135_COARSE_TIME_ADDR_MSB 0x0202
+#define IMX135_COARSE_TIME_ADDR_LSB 0x0203
+#define IMX135_COARSE_TIME_SHORT_ADDR_MSB 0x0230
+#define IMX135_COARSE_TIME_SHORT_ADDR_LSB 0x0231
+#define IMX135_GAIN_ADDR 0x0205
+#define IMX135_GAIN_SHORT_ADDR 0x0233
+
+#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, 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, 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, 0x00},
+       {0x030D, 0xC9},
+       {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, 0x04},
+       {0x0341, 0x92},
+       {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, 0x57},
+       {0x0831, 0x0F},
+       {0x0832, 0x2F},
+       {0x0833, 0x17},
+       {0x0834, 0x0F},
+       {0x0835, 0x0F},
+       {0x0836, 0x47},
+       {0x0837, 0x27},
+       {0x0839, 0x1F},
+       {0x083A, 0x17},
+       {0x083B, 0x02},
+
+       /* Integration Time Setting */
+       {0x0202, 0x04},
+       {0x0203, 0x8E},
+
+       /* 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, 0x00},
+       {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, 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, 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, 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, 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_2104x1560[] = {
+       /* 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, 0x02},
+       {0x030C, 0x01},
+       {0x030D, 0x10},
+       {0x030E, 0x01},
+       {0x3A06, 0x12},
+
+       /* Mode Settings */
+       {0x0108, 0x03},
+       {0x0112, 0x0A},
+       {0x0113, 0x0A},
+       {0x0381, 0x01},
+       {0x0383, 0x01},
+       {0x0385, 0x01},
+       {0x0387, 0x01},
+       {0x0390, 0x01},
+       {0x0391, 0x21},
+       {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, 0x06},
+       {0x0341, 0x30},
+       {0x0342, 0x11},
+       {0x0343, 0xDC},
+       {0x0344, 0x00},
+       {0x0345, 0x00},
+       {0x0346, 0x00},
+       {0x0347, 0x00},
+       {0x0348, 0x10},
+       {0x0349, 0x6F},
+       {0x034A, 0x0C},
+       {0x034B, 0x2F},
+       {0x034C, 0x08},
+       {0x034D, 0x38},
+       {0x034E, 0x06},
+       {0x034F, 0x18},
+       {0x0350, 0x00},
+       {0x0351, 0x00},
+       {0x0352, 0x00},
+       {0x0353, 0x00},
+       {0x0354, 0x08},
+       {0x0355, 0x38},
+       {0x0356, 0x06},
+       {0x0357, 0x18},
+       {0x301D, 0x30},
+       {0x3310, 0x08},
+       {0x3311, 0x38},
+       {0x3312, 0x06},
+       {0x3313, 0x18},
+       {0x331C, 0x00},
+       {0x331D, 0x52},
+       {0x4084, 0x00},
+       {0x4085, 0x00},
+       {0x4086, 0x00},
+       {0x4087, 0x00},
+       {0x4400, 0x00},
+
+       /* Global Timing Setting */
+       {0x0830, 0x5F},
+       {0x0831, 0x17},
+       {0x0832, 0x37},
+       {0x0833, 0x17},
+       {0x0834, 0x17},
+       {0x0835, 0x17},
+       {0x0836, 0x57},
+       {0x0837, 0x27},
+       {0x0839, 0x1F},
+       {0x083A, 0x17},
+       {0x083B, 0x02},
+
+       /* Integration Time Setting */
+       {0x0202, 0x06},
+       {0x0203, 0x2C},
+
+       /* 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, 0x08},
+       {0x33B1, 0x38},
+       {0x33B3, 0x01},
+       {0x33B4, 0x01},
+       {0x3800, 0x00},
+
+       {0x3024, 0xE0},
+       {0x302B, 0x01},
+       {0x302A, 0x01},
+       {0x3029, 0x01},
+       {0x3028, 0x05},
+       {0x3025, 0x00},
+       {0x300C, 0x9C},
+
+       /* stream on */
+       {0x0100, 0x01},
+
+       {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}
+};
+
+static struct imx135_reg tp_colorbars[] = {
+       {0x0600, 0x00},
+       {0x0601, 0x02},
+
+       {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_2104X1560,
+       IMX135_MODE_INVALID
+};
+
+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_2104X1560]  = mode_2104x1560,
+};
+
+static int test_mode;
+module_param(test_mode, int, 0644);
+
+static const struct v4l2_frmsize_discrete imx135_frmsizes[] = {
+       {4208, 3120},
+       {1920, 1080},
+       {1280, 720},
+       {2616, 1472},
+       {3896, 2192},
+       {2104, 1560},
+};
+
+/* Find a data format by a pixel code in an array */
+static const struct imx135_datafmt *imx135_find_datafmt(
+               enum v4l2_mbus_pixelcode code)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(imx135_colour_fmts); i++)
+               if (imx135_colour_fmts[i].code == code)
+                       return imx135_colour_fmts + i;
+
+       return NULL;
+}
+
+#define IMX135_MODE    IMX135_MODE_4208X3120
+#define IMX135_WIDTH   4208
+#define IMX135_HEIGHT  3120
+
+static int imx135_find_mode(struct v4l2_subdev *sd,
+                           u32 width, u32 height)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(imx135_frmsizes); i++) {
+               if (width == imx135_frmsizes[i].width &&
+                   height == imx135_frmsizes[i].height)
+                       return i;
+       }
+
+       dev_err(sd->v4l2_dev->dev, "%dx%d is not supported\n", width, height);
+       return IMX135_MODE_4208X3120;
+}
+
+static inline void msleep_range(unsigned int delay_base)
+{
+       usleep_range(delay_base*1000, delay_base*1000+500);
+}
+
+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[])
+{
+       int err;
+       const struct imx135_reg *next;
+       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;
+
+               err = imx135_write_reg(client, next->addr, val);
+               if (err) {
+                       pr_err("%s:imx135_write_table:%d", __func__, err);
+                       return err;
+               }
+       }
+       return 0;
+}
+
+static void imx135_mclk_disable(struct imx135 *priv)
+{
+       return;
+       dev_dbg(&priv->i2c_client->dev, "%s: disable MCLK\n", __func__);
+       clk_disable_unprepare(priv->mclk);
+}
+
+static int imx135_mclk_enable(struct imx135 *priv)
+{
+       int err;
+       unsigned long mclk_init_rate = 24000000;
+
+       dev_dbg(&priv->i2c_client->dev, "%s: enable MCLK with %lu Hz\n",
+               __func__, mclk_init_rate);
+
+       err = clk_set_rate(priv->mclk, mclk_init_rate);
+       if (!err)
+               err = clk_prepare_enable(priv->mclk);
+       return err;
+}
+
+
+static int imx135_debugfs_show(struct seq_file *s, void *unused)
+{
+       struct imx135 *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 *dev =
+                       ((struct seq_file *)file->private_data)->private;
+       struct i2c_client *i2c_client = dev->i2c_client;
+       int ret = 0;
+       char buffer[MAX_BUFFER_SIZE];
+       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_info(&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 *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 *dev)
+{
+       struct i2c_client *i2c_client = dev->i2c_client;
+
+       dev_dbg(&i2c_client->dev, "%s: ++\n", __func__);
+
+       debugfs_remove_recursive(dev->debugdir);
+       dev->debugdir = NULL;
+}
+
+static void imx135_create_debugfs(struct imx135 *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("imx135", 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_get_extra_regulators(struct imx135_power_rail *pw)
+{
+       struct imx135 *priv = container_of(pw, struct imx135, power);
+       struct i2c_client *client = priv->i2c_client;
+
+       if (!pw->ext_reg1) {
+               pw->ext_reg1 = devm_regulator_get(&client->dev, "imx135_reg1");
+               if (IS_ERR(pw->ext_reg1)) {
+                       dev_err(&client->dev,
+                               "%s: can't get regulator imx135_reg1: %ld\n",
+                               __func__, PTR_ERR(pw->ext_reg1));
+                       pw->ext_reg1 = NULL;
+                       return PTR_ERR(pw->ext_reg1);
+               }
+       }
+
+       if (!pw->ext_reg2) {
+               pw->ext_reg2 = devm_regulator_get(&client->dev, "imx135_reg2");
+               if (IS_ERR(pw->ext_reg2)) {
+                       dev_err(&client->dev,
+                               "%s: can't get regulator imx135_reg2: %ld\n",
+                               __func__, PTR_ERR(pw->ext_reg2));
+                       pw->ext_reg2 = NULL;
+                       return PTR_ERR(pw->ext_reg2);
+               }
+       }
+
+       return 0;
+}
+
+static int imx135_power_on(struct imx135_power_rail *pw)
+{
+       int err;
+       struct imx135 *priv = container_of(pw, struct imx135, power);
+
+       if (unlikely(WARN_ON(!pw || !pw->iovdd || !pw->avdd || !pw->dvdd)))
+               return -EFAULT;
+
+       /* disable CSIA/B IOs DPD mode to turn on camera for ardbeg */
+       tegra_io_dpd_disable(&csia_io);
+       tegra_io_dpd_disable(&csib_io);
+
+       if (imx135_get_extra_regulators(pw))
+               goto imx135_poweron_fail;
+
+       err = regulator_enable(pw->ext_reg1);
+       if (unlikely(err))
+               goto imx135_ext_reg1_fail;
+
+       err = regulator_enable(pw->ext_reg2);
+       if (unlikely(err))
+               goto imx135_ext_reg2_fail;
+
+       gpio_set_value(CAM_RSTN, 0);
+       usleep_range(10, 20);
+       gpio_set_value(CAM_AF_PWDN, 1);
+       gpio_set_value(CAM1_PWDN, 1);
+       usleep_range(10, 20);
+
+       err = regulator_enable(pw->avdd);
+       if (err)
+               goto imx135_avdd_fail;
+
+       err = regulator_enable(pw->iovdd);
+       if (err)
+               goto imx135_iovdd_fail;
+
+       usleep_range(1, 2);
+       gpio_set_value(CAM_RSTN, 1);
+       usleep_range(300, 310);
+
+       return 1;
+
+
+imx135_iovdd_fail:
+       regulator_disable(pw->avdd);
+
+imx135_avdd_fail:
+       if (pw->ext_reg2)
+               regulator_disable(pw->ext_reg2);
+
+imx135_ext_reg2_fail:
+       if (pw->ext_reg1)
+               regulator_disable(pw->ext_reg1);
+       gpio_set_value(priv->pdata->af_gpio, 0);
+
+imx135_ext_reg1_fail:
+imx135_poweron_fail:
+       tegra_io_dpd_enable(&csia_io);
+       tegra_io_dpd_enable(&csib_io);
+       pr_err("%s failed.\n", __func__);
+       return -ENODEV;
+}
+
+static int imx135_power_off(struct imx135_power_rail *pw)
+{
+       return 0;
+
+       if (unlikely(WARN_ON(!pw || !pw->iovdd || !pw->avdd))) {
+               tegra_io_dpd_enable(&csia_io);
+               tegra_io_dpd_enable(&csib_io);
+               return -EFAULT;
+       }
+
+       regulator_disable(pw->iovdd);
+       regulator_disable(pw->avdd);
+
+       regulator_disable(pw->ext_reg1);
+       regulator_disable(pw->ext_reg2);
+
+       /* put CSIA/B IOs into DPD mode to save additional power for ardbeg */
+       tegra_io_dpd_enable(&csia_io);
+       tegra_io_dpd_enable(&csib_io);
+       return 0;
+}
+
+static int imx135_power_put(struct imx135_power_rail *pw)
+{
+       if (unlikely(!pw))
+               return -EFAULT;
+
+       pw->avdd = NULL;
+       pw->iovdd = NULL;
+       pw->dvdd = NULL;
+       pw->ext_reg1 = NULL;
+       pw->ext_reg2 = NULL;
+
+       return 0;
+}
+
+static int imx135_power_get(struct imx135 *priv)
+{
+       struct imx135_power_rail *pw = &priv->power;
+       int err;
+
+       /* ananlog 2.7v */
+       pw->avdd = devm_regulator_get(&priv->i2c_client->dev, "vana");
+       if (IS_ERR(pw->avdd)) {
+               err = PTR_ERR(pw->avdd);
+               pw->avdd = NULL;
+               dev_err(&priv->i2c_client->dev, "Failed to get regulator vana\n");
+               return err;
+       }
+
+       /* digital 1.2v */
+       pw->dvdd = devm_regulator_get(&priv->i2c_client->dev, "vdig");
+       if (IS_ERR(pw->dvdd)) {
+               err = PTR_ERR(pw->dvdd);
+               pw->dvdd = NULL;
+               dev_err(&priv->i2c_client->dev, "Failed to get regulator vdig\n");
+               return err;
+       }
+
+       /* IO 1.8v */
+       pw->iovdd = devm_regulator_get(&priv->i2c_client->dev, "vif");
+       if (IS_ERR(pw->iovdd)) {
+               err = PTR_ERR(pw->iovdd);
+               pw->iovdd = NULL;
+               dev_err(&priv->i2c_client->dev, "Failed to get regulator vif\n");
+               return err;
+       }
+
+       return 0;
+}
+
+static int imx135_try_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct imx135 *priv = to_imx135(client);
+       int mode = imx135_find_mode(sd, mf->width, mf->height);
+
+       mf->width = imx135_frmsizes[mode].width;
+       mf->height = imx135_frmsizes[mode].height;
+
+       if (mf->code != V4L2_MBUS_FMT_SRGGB8_1X8 &&
+           mf->code != V4L2_MBUS_FMT_SRGGB10_1X10)
+               mf->code = V4L2_MBUS_FMT_SRGGB10_1X10;
+
+       mf->field = V4L2_FIELD_NONE;
+       mf->colorspace = V4L2_COLORSPACE_SRGB;
+
+       priv->mode = mode;
+
+       return 0;
+}
+
+static int imx135_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct imx135 *priv = to_imx135(client);
+
+       dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code);
+
+       /* MIPI CSI could have changed the format, double-check */
+       if (!imx135_find_datafmt(mf->code))
+               return -EINVAL;
+
+       imx135_try_fmt(sd, mf);
+
+       priv->fmt = imx135_find_datafmt(mf->code);
+
+       return 0;
+}
+
+static int imx135_g_fmt(struct v4l2_subdev *sd,        struct v4l2_mbus_framefmt *mf)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct imx135 *priv = to_imx135(client);
+
+       const struct imx135_datafmt *fmt = priv->fmt;
+
+       mf->code        = fmt->code;
+       mf->colorspace  = fmt->colorspace;
+       mf->width       = IMX135_WIDTH;
+       mf->height      = IMX135_HEIGHT;
+       mf->field       = V4L2_FIELD_NONE;
+
+       return 0;
+}
+
+static int imx135_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+       struct v4l2_rect *rect = &a->c;
+
+       a->type         = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       rect->top       = 0;
+       rect->left      = 0;
+       rect->width     = IMX135_WIDTH;
+       rect->height    = IMX135_HEIGHT;
+
+       return 0;
+}
+
+static int imx135_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+       a->bounds.left                  = 0;
+       a->bounds.top                   = 0;
+       a->bounds.width                 = IMX135_WIDTH;
+       a->bounds.height                = IMX135_HEIGHT;
+       a->defrect                      = a->bounds;
+       a->type                         = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       a->pixelaspect.numerator        = 1;
+       a->pixelaspect.denominator      = 1;
+
+       return 0;
+}
+
+static int imx135_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+                          enum v4l2_mbus_pixelcode *code)
+{
+       if ((unsigned int)index >= ARRAY_SIZE(imx135_colour_fmts))
+               return -EINVAL;
+
+       *code = imx135_colour_fmts[index].code;
+       return 0;
+}
+
+static int imx135_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct imx135 *priv = to_imx135(client);
+       int err = 0;
+
+       if (!enable)
+               return 0;
+
+       err = imx135_write_table(priv->i2c_client, mode_table[priv->mode]);
+       if (err)
+               return err;
+
+       if (test_mode)
+               imx135_write_table(priv->i2c_client, tp_colorbars);
+
+       err = imx135_write_table(priv->i2c_client, mode_quality);
+       if (err)
+               return err;
+
+       return err;
+}
+
+static int imx135_g_chip_ident(struct v4l2_subdev *sd,
+                              struct v4l2_dbg_chip_ident *id)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+       if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
+               return -EINVAL;
+
+       if (id->match.addr != client->addr)
+               return -ENODEV;
+
+       id->ident       = V4L2_IDENT_IMX135;
+       id->revision    = 0;
+
+       return 0;
+}
+
+static int imx135_s_power(struct v4l2_subdev *sd, int on)
+{
+       struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct imx135 *priv = to_imx135(client);
+       int err;
+
+       if (on) {
+               err = imx135_mclk_enable(priv);
+               if (!err)
+                       err = imx135_power_on(&priv->power);
+               if (err < 0)
+                       imx135_mclk_disable(priv);
+               return err;
+       } else if (!on) {
+               imx135_power_off(&priv->power);
+               imx135_mclk_disable(priv);
+               return 0;
+       } else
+               return -EINVAL;
+}
+
+static int imx135_g_mbus_config(struct v4l2_subdev *sd,
+                               struct v4l2_mbus_config *cfg)
+{
+       cfg->type = V4L2_MBUS_CSI2;
+       cfg->flags = V4L2_MBUS_CSI2_4_LANE |
+               V4L2_MBUS_CSI2_CHANNEL_0 |
+               V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
+
+       return 0;
+}
+
+static struct v4l2_subdev_video_ops imx135_subdev_video_ops = {
+       .s_stream       = imx135_s_stream,
+       .s_mbus_fmt     = imx135_s_fmt,
+       .g_mbus_fmt     = imx135_g_fmt,
+       .try_mbus_fmt   = imx135_try_fmt,
+       .enum_mbus_fmt  = imx135_enum_fmt,
+       .g_crop         = imx135_g_crop,
+       .cropcap        = imx135_cropcap,
+       .g_mbus_config  = imx135_g_mbus_config,
+};
+
+static struct v4l2_subdev_core_ops imx135_subdev_core_ops = {
+       .g_chip_ident   = imx135_g_chip_ident,
+       .s_power        = imx135_s_power,
+};
+
+static struct v4l2_subdev_ops imx135_subdev_ops = {
+       .core   = &imx135_subdev_core_ops,
+       .video  = &imx135_subdev_video_ops,
+};
+
+static struct of_device_id imx135_of_match[] = {
+       { .compatible = "nvidia,imx135", },
+       { },
+};
+
+MODULE_DEVICE_TABLE(of, imx135_of_match);
+
+static struct imx135_platform_data *imx135_parse_dt(struct i2c_client *client)
+{
+       struct device_node *np = client->dev.of_node;
+       struct imx135_platform_data *board_priv_pdata;
+       const struct of_device_id *match;
+
+       match = of_match_device(imx135_of_match, &client->dev);
+       if (!match) {
+               dev_err(&client->dev, "Failed to find matching dt id\n");
+               return NULL;
+       }
+
+       board_priv_pdata = devm_kzalloc(&client->dev, sizeof(*board_priv_pdata),
+                       GFP_KERNEL);
+       if (!board_priv_pdata) {
+               dev_err(&client->dev, "Failed to allocate pdata\n");
+               return NULL;
+       }
+
+       board_priv_pdata->cam1_gpio = of_get_named_gpio(np, "cam1-gpios", 0);
+       board_priv_pdata->reset_gpio = of_get_named_gpio(np, "reset-gpios", 0);
+       board_priv_pdata->af_gpio = of_get_named_gpio(np, "af-gpios", 0);
+
+       board_priv_pdata->ext_reg = of_property_read_bool(np, "nvidia,ext_reg");
+
+       board_priv_pdata->power_on = imx135_power_on;
+       board_priv_pdata->power_off = imx135_power_off;
+
+       return board_priv_pdata;
+}
+
+static int imx135_get_sensor_id(struct imx135 *priv)
+{
+       int i;
+       u8 bak = 0, fuse_id[16];
+
+       imx135_mclk_enable(priv);
+       imx135_power_on(&priv->power);
+
+       imx135_write_reg(priv->i2c_client, 0x3B02, 0x00);
+       imx135_write_reg(priv->i2c_client, 0x3B00, 0x01);
+
+       for (i = 0; i < 9; i++) {
+               imx135_read_reg(priv->i2c_client, 0x3B24 + i, &bak);
+               fuse_id[i] = bak;
+       }
+
+       imx135_power_off(&priv->power);
+       imx135_mclk_disable(priv);
+
+       return 0;
+}
+
+static int imx135_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       struct imx135 *priv;
+       const char *mclk_name;
+       int err;
+
+       priv = devm_kzalloc(&client->dev,
+                       sizeof(struct imx135), GFP_KERNEL);
+       if (!priv) {
+               dev_err(&client->dev, "unable to allocate memory!\n");
+               return -ENOMEM;
+       }
+
+       if (client->dev.of_node)
+               priv->pdata = imx135_parse_dt(client);
+       else
+               priv->pdata = client->dev.platform_data;
+
+       if (!priv->pdata) {
+               dev_err(&client->dev, "unable to get platform data\n");
+               return -EFAULT;
+       }
+
+       priv->i2c_client = client;
+       priv->mode = IMX135_MODE;
+       priv->fmt = &imx135_colour_fmts[0];
+
+       mclk_name = priv->pdata->mclk_name ?
+                   priv->pdata->mclk_name : "default_mclk";
+       priv->mclk = devm_clk_get(&client->dev, mclk_name);
+       if (IS_ERR(priv->mclk)) {
+               dev_err(&client->dev, "unable to get clock %s\n", mclk_name);
+               return PTR_ERR(priv->mclk);
+       }
+
+       err = imx135_power_get(priv);
+       if (err)
+               return err;
+
+       i2c_set_clientdata(client, priv);
+
+       imx135_get_sensor_id(priv);
+
+       imx135_create_debugfs(priv);
+
+       v4l2_i2c_subdev_init(&priv->subdev, client, &imx135_subdev_ops);
+
+       return 0;
+}
+
+static int
+imx135_remove(struct i2c_client *client)
+{
+       struct soc_camera_subdev_desc *ssdd;
+       struct imx135 *priv;
+
+       ssdd = soc_camera_i2c_to_desc(client);
+       if (ssdd->free_bus)
+               ssdd->free_bus(ssdd);
+
+       priv = i2c_get_clientdata(client);
+       imx135_power_put(&priv->power);
+       imx135_remove_debugfs(priv);
+
+       return 0;
+}
+
+static const struct i2c_device_id imx135_id[] = {
+       { "imx135_v4l2", 0 },
+       { }
+};
+
+MODULE_DEVICE_TABLE(i2c, imx135_id);
+
+static struct i2c_driver imx135_i2c_driver = {
+       .driver = {
+               .name = "imx135_v4l2",
+               .owner = THIS_MODULE,
+       },
+       .probe = imx135_probe,
+       .remove = imx135_remove,
+       .id_table = imx135_id,
+};
+
+module_i2c_driver(imx135_i2c_driver);
+
+MODULE_DESCRIPTION("SoC Camera driver for Sony IMX135");
+MODULE_AUTHOR("Bryan Wu <pengw@nvidia.com>");
+MODULE_LICENSE("GPL v2");
index b8e14c942a345e4a2b2fed0c10ef01f62e254e42..4269b291cbdf423972567f71de25b9a1e67c66b1 100644 (file)
@@ -40,6 +40,7 @@ enum {
 
        /* Sony IMX074 */
        V4L2_IDENT_IMX074 = 74,
+       V4L2_IDENT_IMX135 = 75,
 
        /* module saa7110: just ident 100 */
        V4L2_IDENT_SAA7110 = 100,