diff options
author | Bryan Wu <pengw@nvidia.com> | 2013-11-19 15:51:20 -0800 |
---|---|---|
committer | Winnie Hsu <whsu@nvidia.com> | 2014-09-26 10:48:52 -0700 |
commit | a4201ceac4a89a495d759885b1e2d5a1c1466073 (patch) | |
tree | 637f5fcbe7908d6bec6c275bec2cf53a2c2b5047 /drivers/media | |
parent | 4a15e35dbfd2bc14b6fe9a2a0bf8a33f624182e5 (diff) |
media: soc_camera: add imx135 sensor driver
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
(cherry picked from commit 94a04c2c9b614519aab6f718d60bcf1d8032aa8f)
Reviewed-on: http://git-master/r/498935
GVS: Gerrit_Virtual_Submit
Reviewed-by: Matthew Pedro <mapedro@nvidia.com>
Reviewed-by: Winnie Hsu <whsu@nvidia.com>
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/i2c/soc_camera/Kconfig | 6 | ||||
-rw-r--r-- | drivers/media/i2c/soc_camera/Makefile | 1 | ||||
-rw-r--r-- | drivers/media/i2c/soc_camera/imx135_v4l2.c | 2426 |
3 files changed, 2433 insertions, 0 deletions
diff --git a/drivers/media/i2c/soc_camera/Kconfig b/drivers/media/i2c/soc_camera/Kconfig index 764d06c1a207..a1b9b709f052 100644 --- a/drivers/media/i2c/soc_camera/Kconfig +++ b/drivers/media/i2c/soc_camera/Kconfig @@ -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 diff --git a/drivers/media/i2c/soc_camera/Makefile b/drivers/media/i2c/soc_camera/Makefile index 63209a902b9d..fe0c86b92aa2 100644 --- a/drivers/media/i2c/soc_camera/Makefile +++ b/drivers/media/i2c/soc_camera/Makefile @@ -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 index 000000000000..eda645326201 --- /dev/null +++ b/drivers/media/i2c/soc_camera/imx135_v4l2.c @@ -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"); |