From 39402a58f139863c70eb18f8fa927471f36f228a Mon Sep 17 00:00:00 2001 From: Ming Wong Date: Fri, 16 Nov 2012 17:34:31 -0800 Subject: media: video: tegra: add imx135 HDR sensor Added driver support for imx135 HDR sensor. Bug 1250073 Change-Id: I291051453f24ddbb058ad195b1c2e1bf0c7f118e Signed-off-by: Frank Chen Signed-off-by: Ming Wong Reviewed-on: http://git-master/r/206759 Reviewed-by: Bharat Nihalani Tested-by: Bharat Nihalani --- drivers/media/video/tegra/Kconfig | 7 + drivers/media/video/tegra/Makefile | 1 + drivers/media/video/tegra/imx135.c | 2401 ++++++++++++++++++++++++++++++++++++ 3 files changed, 2409 insertions(+) create mode 100644 drivers/media/video/tegra/imx135.c (limited to 'drivers') diff --git a/drivers/media/video/tegra/Kconfig b/drivers/media/video/tegra/Kconfig index 8d59c895a6e4..79c403202348 100644 --- a/drivers/media/video/tegra/Kconfig +++ b/drivers/media/video/tegra/Kconfig @@ -68,6 +68,13 @@ config VIDEO_IMX091 This is a driver for the IMX091 camera sensor for use with the tegra isp. +config VIDEO_IMX135 + tristate "IMX135 camera sensor support" + depends on I2C && ARCH_TEGRA + ---help--- + This is a driver for the IMX135 camera sensor + for use with the tegra isp. + config VIDEO_IMX132 tristate "IMX132 camera sensor support" depends on I2C && ARCH_TEGRA diff --git a/drivers/media/video/tegra/Makefile b/drivers/media/video/tegra/Makefile index d643b3a71d4b..92538d0a9c44 100644 --- a/drivers/media/video/tegra/Makefile +++ b/drivers/media/video/tegra/Makefile @@ -24,4 +24,5 @@ obj-$(CONFIG_VIDEO_SH532U) += sh532u.o obj-$(CONFIG_VIDEO_AD5820) += ad5820.o obj-$(CONFIG_VIDEO_AD5816) += ad5816.o obj-$(CONFIG_VIDEO_IMX091) += imx091.o +obj-$(CONFIG_VIDEO_IMX135) += imx135.o obj-$(CONFIG_VIDEO_IMX132) += imx132.o diff --git a/drivers/media/video/tegra/imx135.c b/drivers/media/video/tegra/imx135.c new file mode 100644 index 000000000000..ff287a219add --- /dev/null +++ b/drivers/media/video/tegra/imx135.c @@ -0,0 +1,2401 @@ +/* + * imx135.c - imx135 sensor driver + * + * 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +struct imx135_reg { + u16 addr; + u8 val; +}; + +struct imx135_info { + struct miscdevice miscdev_info; + int mode; + struct imx135_power_rail power; + struct imx135_sensordata sensor_data; + struct i2c_client *i2c_client; + struct imx135_platform_data *pdata; + struct mutex imx135_camera_lock; + struct dentry *debugdir; + atomic_t in_use; +}; + +#define IMX135_TABLE_WAIT_MS 0 +#define IMX135_TABLE_END 1 +#define IMX135_MAX_RETRIES 3 +#define IMX135_WAIT_MS 3 + +#define IMX135_4208x3120_HDR + +#ifdef IMX135_4208x3120_HDR +/* HDR */ +static struct imx135_reg mode_4208x3120[] = { + /* software standby */ + {0x0100, 0x00}, + /* global settings */ + {0x0101, 0x00}, + {0x0105, 0x01}, + {0x0110, 0x00}, + {0x0220, 0x01}, + {0x3302, 0x11}, + {0x3833, 0x20}, + {0x3873, 0x03}, + {0x3893, 0x00}, + {0x3906, 0x08}, + {0x3907, 0x01}, + {0x391B, 0x00}, + {0x3C09, 0x01}, + {0x600A, 0x00}, + {0x3008, 0xB0}, + {0x320A, 0x01}, + {0x320D, 0x10}, + {0x3216, 0x2E}, + {0x322C, 0x02}, + {0x3409, 0x0C}, + {0x340C, 0x2D}, + {0x3411, 0x39}, + {0x3414, 0x1E}, + {0x3427, 0x04}, + {0x3480, 0x1E}, + {0x3484, 0x1E}, + {0x3488, 0x1E}, + {0x348C, 0x1E}, + {0x3490, 0x1E}, + {0x3494, 0x1E}, + {0x3511, 0x8F}, + {0x364F, 0x2D}, + + /* Clock Setting */ + {0x011E, 0x18}, + {0x011F, 0x00}, + {0x0301, 0x05}, + {0x0303, 0x01}, + {0x0305, 0x0C}, + {0x0309, 0x05}, + {0x030B, 0x01}, + {0x030C, 0x01}, + {0x030D, 0xC2}, + {0x030E, 0x01}, + {0x3A06, 0x11}, + + /* Mode Settings */ + {0x0108, 0x03}, + {0x0112, 0x0E}, + {0x0113, 0x0A}, + {0x0381, 0x01}, + {0x0383, 0x01}, + {0x0385, 0x01}, + {0x0387, 0x01}, + {0x0390, 0x00}, + {0x0391, 0x11}, + {0x0392, 0x00}, + {0x0401, 0x00}, + {0x0404, 0x00}, + {0x0405, 0x10}, + {0x4082, 0x01}, + {0x4083, 0x01}, + {0x7006, 0x04}, + + /* Optinal/Function settings */ + {0x0700, 0x00}, + {0x3A63, 0x00}, + {0x4100, 0xF8}, + {0x4203, 0xFF}, + {0x4344, 0x00}, + {0x441C, 0x01}, + + /* Size Setting */ + {0x0340, 0x0C}, + {0x0341, 0xD0}, + {0x0342, 0x11}, + {0x0343, 0xDC}, + {0x0344, 0x00}, + {0x0345, 0x00}, + {0x0346, 0x00}, + {0x0347, 0x00}, + {0x0348, 0x10}, + {0x0349, 0x6F}, + {0x034A, 0x0C}, + {0x034B, 0x2F}, + {0x034C, 0x10}, + {0x034D, 0x70}, + {0x034E, 0x0C}, + {0x034F, 0x30}, + {0x0350, 0x00}, + {0x0351, 0x00}, + {0x0352, 0x00}, + {0x0353, 0x00}, + {0x0354, 0x10}, + {0x0355, 0x70}, + {0x0356, 0x0C}, + {0x0357, 0x30}, + {0x301D, 0x30}, + {0x3310, 0x10}, + {0x3311, 0x70}, + {0x3312, 0x0C}, + {0x3313, 0x30}, + {0x331C, 0x01}, + {0x331D, 0x68}, + {0x4084, 0x00}, + {0x4085, 0x00}, + {0x4086, 0x00}, + {0x4087, 0x00}, + {0x4400, 0x00}, + + /* Global Timing Setting */ + {0x0830, 0x87}, + {0x0831, 0x3F}, + {0x0832, 0x67}, + {0x0833, 0x3F}, + {0x0834, 0x3F}, + {0x0835, 0x4F}, + {0x0836, 0xDF}, + {0x0837, 0x47}, + {0x0839, 0x1F}, + {0x083A, 0x17}, + {0x083B, 0x02}, + + /* Integration Time Setting */ + {0x0202, 0x0C}, + {0x0203, 0xCC}, + + /* Gain Setting */ + {0x0205, 0x00}, + {0x020E, 0x01}, + {0x020F, 0x00}, + {0x0210, 0x01}, + {0x0211, 0x00}, + {0x0212, 0x01}, + {0x0213, 0x00}, + {0x0214, 0x01}, + {0x0215, 0x00}, + + /* HDR Setting */ + {0x0230, 0x00}, + {0x0231, 0x00}, + {0x0233, 0x00}, + {0x0234, 0x00}, + {0x0235, 0x40}, + {0x0238, 0x01}, + {0x0239, 0x04}, + {0x023B, 0x00}, + {0x023C, 0x01}, + {0x33B0, 0x10}, + {0x33B1, 0x70}, + {0x33B3, 0x01}, + {0x33B4, 0x01}, + {0x3800, 0x00}, + + {0x3A43, 0x01}, + /* stream on */ + {0x0100, 0x01}, + + {IMX135_TABLE_WAIT_MS, IMX135_WAIT_MS}, + {IMX135_TABLE_END, 0x00} +}; +#else +/* standard */ +static struct imx135_reg mode_4208x3120[] = { + /* software standby */ + {0x0100, 0x00}, + /* 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 standby */ + {0x0100, 0x00}, + /* global settings */ + {0x0101, 0x00}, + {0x0105, 0x01}, + {0x0110, 0x00}, + {0x0220, 0x01}, + {0x3302, 0x11}, + {0x3833, 0x20}, + {0x3893, 0x00}, + {0x3906, 0x08}, + {0x3907, 0x01}, + {0x391B, 0x01}, + {0x3C09, 0x01}, + {0x600A, 0x00}, + {0x3008, 0xB0}, + {0x320A, 0x01}, + {0x320D, 0x10}, + {0x3216, 0x2E}, + {0x322C, 0x02}, + {0x3409, 0x0C}, + {0x340C, 0x2D}, + {0x3411, 0x39}, + {0x3414, 0x1E}, + {0x3427, 0x04}, + {0x3480, 0x1E}, + {0x3484, 0x1E}, + {0x3488, 0x1E}, + {0x348C, 0x1E}, + {0x3490, 0x1E}, + {0x3494, 0x1E}, + {0x3511, 0x8F}, + {0x364F, 0x2D}, + + /* Clock Setting */ + {0x011E, 0x18}, + {0x011F, 0x00}, + {0x0301, 0x05}, + {0x0303, 0x01}, + {0x0305, 0x0C}, + {0x0309, 0x05}, + {0x030B, 0x02}, + {0x030C, 0x01}, + {0x030D, 0xC2}, + {0x030E, 0x01}, + {0x3A06, 0x12}, + + /* Mode Settings */ + {0x0108, 0x03}, + {0x0112, 0x0A}, + {0x0113, 0x0A}, + {0x0381, 0x01}, + {0x0383, 0x01}, + {0x0385, 0x01}, + {0x0387, 0x01}, + {0x0390, 0x01}, + {0x0391, 0x22}, + {0x0392, 0x00}, + {0x0401, 0x02}, + {0x0404, 0x00}, + {0x0405, 0x11}, + {0x4082, 0x00}, + {0x4083, 0x00}, + {0x7006, 0x04}, + + /* Optinal/Function settings */ + {0x0700, 0x00}, + {0x3A63, 0x00}, + {0x4100, 0xF8}, + {0x4203, 0xFF}, + {0x4344, 0x00}, + {0x441C, 0x01}, + + /* Size Setting */ + {0x0340, 0x0A}, + {0x0341, 0x40}, + {0x0342, 0x11}, + {0x0343, 0xDC}, + {0x0344, 0x00}, + {0x0345, 0x40}, + {0x0346, 0x01}, + {0x0347, 0x9C}, + {0x0348, 0x10}, + {0x0349, 0x2F}, + {0x034A, 0x0A}, + {0x034B, 0x93}, + {0x034C, 0x07}, + {0x034D, 0x80}, + {0x034E, 0x04}, + {0x034F, 0x38}, + {0x0350, 0x00}, + {0x0351, 0x00}, + {0x0352, 0x00}, + {0x0353, 0x00}, + {0x0354, 0x07}, + {0x0355, 0xF8}, + {0x0356, 0x04}, + {0x0357, 0x7C}, + {0x301D, 0x30}, + {0x3310, 0x07}, + {0x3311, 0x80}, + {0x3312, 0x04}, + {0x3313, 0x38}, + {0x331C, 0x00}, + {0x331D, 0xD2}, + {0x4084, 0x07}, + {0x4085, 0x80}, + {0x4086, 0x04}, + {0x4087, 0x38}, + {0x4400, 0x00}, + + /* Global Timing Setting */ + {0x0830, 0x67}, + {0x0831, 0x27}, + {0x0832, 0x47}, + {0x0833, 0x27}, + {0x0834, 0x27}, + {0x0835, 0x1F}, + {0x0836, 0x87}, + {0x0837, 0x2F}, + {0x0839, 0x1F}, + {0x083A, 0x17}, + {0x083B, 0x02}, + + /* Integration Time Setting */ + {0x0202, 0x0A}, + {0x0203, 0x3C}, + + /* Gain Setting */ + {0x0205, 0x00}, + {0x020E, 0x01}, + {0x020F, 0x00}, + {0x0210, 0x01}, + {0x0211, 0x00}, + {0x0212, 0x01}, + {0x0213, 0x00}, + {0x0214, 0x01}, + {0x0215, 0x00}, + + /* HDR Setting */ + {0x0230, 0x00}, + {0x0231, 0x00}, + {0x0233, 0x00}, + {0x0234, 0x00}, + {0x0235, 0x40}, + {0x0238, 0x01}, + {0x0239, 0x04}, + {0x023B, 0x00}, + {0x023C, 0x01}, + {0x33B0, 0x04}, + {0x33B1, 0x00}, + {0x33B3, 0x00}, + {0x33B4, 0x01}, + {0x3800, 0x00}, + + {0x3A43, 0x01}, + /* stream on */ + {0x0100, 0x01}, + + {IMX135_TABLE_WAIT_MS, IMX135_WAIT_MS}, + {IMX135_TABLE_END, 0x00} +}; + +#ifdef IMX135_1280x720_90_FPS +/* 720p 90fps */ +static struct imx135_reg mode_1280x720[] = { + /* software standby */ + {0x0100, 0x00}, + /* 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 standby */ + {0x0100, 0x00}, + /* 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 standby */ + {0x0100, 0x00}, + /* global settings */ + {0x0101, 0x00}, + {0x0105, 0x01}, + {0x0110, 0x00}, + {0x0220, 0x01}, + {0x3302, 0x11}, + {0x3833, 0x20}, + {0x3873, 0x03}, + {0x3893, 0x00}, + {0x3906, 0x08}, + {0x3907, 0x01}, + {0x391B, 0x00}, + {0x3C09, 0x01}, + {0x600A, 0x00}, + {0x3008, 0xB0}, + {0x320A, 0x01}, + {0x320D, 0x10}, + {0x3216, 0x2E}, + {0x322C, 0x02}, + {0x3409, 0x0C}, + {0x340C, 0x2D}, + {0x3411, 0x39}, + {0x3414, 0x1E}, + {0x3427, 0x04}, + {0x3480, 0x1E}, + {0x3484, 0x1E}, + {0x3488, 0x1E}, + {0x348C, 0x1E}, + {0x3490, 0x1E}, + {0x3494, 0x1E}, + {0x3511, 0x8F}, + {0x364F, 0x2D}, + + /* Clock Setting */ + {0x011E, 0x18}, + {0x011F, 0x00}, + {0x0301, 0x05}, + {0x0303, 0x01}, + {0x0305, 0x0C}, + {0x0309, 0x05}, + {0x030B, 0x01}, + {0x030C, 0x01}, + {0x030D, 0xC2}, + {0x030E, 0x01}, + {0x3A06, 0x11}, + + /* Mode Settings */ + {0x0108, 0x03}, + {0x0112, 0x0E}, + {0x0113, 0x0A}, + {0x0381, 0x01}, + {0x0383, 0x01}, + {0x0385, 0x01}, + {0x0387, 0x01}, + {0x0390, 0x00}, + {0x0391, 0x11}, + {0x0392, 0x00}, + {0x0401, 0x00}, + {0x0404, 0x00}, + {0x0405, 0x10}, + {0x4082, 0x01}, + {0x4083, 0x01}, + {0x7006, 0x04}, + + /* Optinal/Function settings */ + {0x0700, 0x00}, + {0x3A63, 0x00}, + {0x4100, 0xF8}, + {0x4203, 0xFF}, + {0x4344, 0x00}, + {0x441C, 0x01}, + + /* Size Setting */ + {0x0340, 0x0A}, + {0x0341, 0x40}, + {0x0342, 0x11}, + {0x0343, 0xDC}, + {0x0344, 0x03}, + {0x0345, 0x1C}, + {0x0346, 0x03}, + {0x0347, 0x38}, + {0x0348, 0x0D}, + {0x0349, 0x53}, + {0x034A, 0x08}, + {0x034B, 0xF7}, + {0x034C, 0x0A}, + {0x034D, 0x38}, + {0x034E, 0x05}, + {0x034F, 0xC0}, + {0x0350, 0x00}, + {0x0351, 0x00}, + {0x0352, 0x00}, + {0x0353, 0x00}, + {0x0354, 0x0A}, + {0x0355, 0x38}, + {0x0356, 0x05}, + {0x0357, 0xC0}, + {0x301D, 0x30}, + {0x3310, 0x0A}, + {0x3311, 0x38}, + {0x3312, 0x05}, + {0x3313, 0xC0}, + {0x331C, 0x08}, + {0x331D, 0xD4}, + {0x4084, 0x00}, + {0x4085, 0x00}, + {0x4086, 0x00}, + {0x4087, 0x00}, + {0x4400, 0x00}, + + /* Global Timing Setting */ + {0x0830, 0x87}, + {0x0831, 0x3F}, + {0x0832, 0x67}, + {0x0833, 0x3F}, + {0x0834, 0x3F}, + {0x0835, 0x4F}, + {0x0836, 0xDF}, + {0x0837, 0x47}, + {0x0839, 0x1F}, + {0x083A, 0x17}, + {0x083B, 0x02}, + + /* Integration Time Setting */ + {0x0202, 0x0A}, + {0x0203, 0x3C}, + + /* Gain Setting */ + {0x0205, 0x00}, + {0x020E, 0x01}, + {0x020F, 0x00}, + {0x0210, 0x01}, + {0x0211, 0x00}, + {0x0212, 0x01}, + {0x0213, 0x00}, + {0x0214, 0x01}, + {0x0215, 0x00}, + + /* HDR Setting */ + {0x0230, 0x00}, + {0x0231, 0x00}, + {0x0233, 0x00}, + {0x0234, 0x00}, + {0x0235, 0x40}, + {0x0238, 0x01}, + {0x0239, 0x04}, + {0x023B, 0x00}, + {0x023C, 0x01}, + {0x33B0, 0x0A}, + {0x33B1, 0x38}, + {0x33B3, 0x01}, + {0x33B4, 0x01}, + {0x3800, 0x00}, + + {0x3A43, 0x01}, + /* stream on */ + {0x0100, 0x01}, + + {IMX135_TABLE_WAIT_MS, IMX135_WAIT_MS}, + {IMX135_TABLE_END, 0x00} +}; + +static struct imx135_reg mode_3896x2192[] = { + /* software standby */ + {0x0100, 0x00}, + /* global settings */ + {0x0101, 0x00}, + {0x0105, 0x01}, + {0x0110, 0x00}, + {0x0220, 0x01}, + {0x3302, 0x11}, + {0x3833, 0x20}, + {0x3873, 0x03}, + {0x3893, 0x00}, + {0x3906, 0x08}, + {0x3907, 0x01}, + {0x391B, 0x00}, + {0x3C09, 0x01}, + {0x600A, 0x00}, + {0x3008, 0xB0}, + {0x320A, 0x01}, + {0x320D, 0x10}, + {0x3216, 0x2E}, + {0x322C, 0x02}, + {0x3409, 0x0C}, + {0x340C, 0x2D}, + {0x3411, 0x39}, + {0x3414, 0x1E}, + {0x3427, 0x04}, + {0x3480, 0x1E}, + {0x3484, 0x1E}, + {0x3488, 0x1E}, + {0x348C, 0x1E}, + {0x3490, 0x1E}, + {0x3494, 0x1E}, + {0x3511, 0x8F}, + {0x364F, 0x2D}, + + /* Clock Setting */ + {0x011E, 0x18}, + {0x011F, 0x00}, + {0x0301, 0x05}, + {0x0303, 0x01}, + {0x0305, 0x0C}, + {0x0309, 0x05}, + {0x030B, 0x01}, + {0x030C, 0x01}, + {0x030D, 0xC2}, + {0x030E, 0x01}, + {0x3A06, 0x11}, + + /* Mode Settings */ + {0x0108, 0x03}, + {0x0112, 0x0E}, + {0x0113, 0x0A}, + {0x0381, 0x01}, + {0x0383, 0x01}, + {0x0385, 0x01}, + {0x0387, 0x01}, + {0x0390, 0x00}, + {0x0391, 0x11}, + {0x0392, 0x00}, + {0x0401, 0x00}, + {0x0404, 0x00}, + {0x0405, 0x10}, + {0x4082, 0x01}, + {0x4083, 0x01}, + {0x7006, 0x04}, + + /* Optinal/Function settings */ + {0x0700, 0x00}, + {0x3A63, 0x00}, + {0x4100, 0xF8}, + {0x4203, 0xFF}, + {0x4344, 0x00}, + {0x441C, 0x01}, + + /* Size Setting */ + {0x0340, 0x0A}, + {0x0341, 0x40}, + {0x0342, 0x11}, + {0x0343, 0xDC}, + {0x0344, 0x00}, + {0x0345, 0x9C}, + {0x0346, 0x01}, + {0x0347, 0xD0}, + {0x0348, 0x0F}, + {0x0349, 0xD3}, + {0x034A, 0x0A}, + {0x034B, 0x5F}, + {0x034C, 0x0F}, + {0x034D, 0x38}, + {0x034E, 0x08}, + {0x034F, 0x90}, + {0x0350, 0x00}, + {0x0351, 0x00}, + {0x0352, 0x00}, + {0x0353, 0x00}, + {0x0354, 0x0F}, + {0x0355, 0x38}, + {0x0356, 0x08}, + {0x0357, 0x90}, + {0x301D, 0x30}, + {0x3310, 0x0F}, + {0x3311, 0x38}, + {0x3312, 0x08}, + {0x3313, 0x90}, + {0x331C, 0x0F}, + {0x331D, 0x32}, + {0x4084, 0x00}, + {0x4085, 0x00}, + {0x4086, 0x00}, + {0x4087, 0x00}, + {0x4400, 0x00}, + + /* Global Timing Setting */ + {0x0830, 0x87}, + {0x0831, 0x3F}, + {0x0832, 0x67}, + {0x0833, 0x3F}, + {0x0834, 0x3F}, + {0x0835, 0x4F}, + {0x0836, 0xDF}, + {0x0837, 0x47}, + {0x0839, 0x1F}, + {0x083A, 0x17}, + {0x083B, 0x02}, + + /* Integration Time Setting */ + {0x0202, 0x0A}, + {0x0203, 0x3C}, + + /* Gain Setting */ + {0x0205, 0x00}, + {0x020E, 0x01}, + {0x020F, 0x00}, + {0x0210, 0x01}, + {0x0211, 0x00}, + {0x0212, 0x01}, + {0x0213, 0x00}, + {0x0214, 0x01}, + {0x0215, 0x00}, + + /* HDR Setting */ + {0x0230, 0x00}, + {0x0231, 0x00}, + {0x0233, 0x00}, + {0x0234, 0x00}, + {0x0235, 0x40}, + {0x0238, 0x01}, + {0x0239, 0x04}, + {0x023B, 0x00}, + {0x023C, 0x01}, + {0x33B0, 0x0F}, + {0x33B1, 0x38}, + {0x33B3, 0x01}, + {0x33B4, 0x01}, + {0x3800, 0x00}, + + {0x3A43, 0x01}, + /* stream on */ + {0x0100, 0x01}, + + {IMX135_TABLE_WAIT_MS, IMX135_WAIT_MS}, + {IMX135_TABLE_END, 0x00} +}; + +static struct imx135_reg mode_quality_hdr[] = { + /* defect correction */ + {0x380A, 0x00}, + {0x380B, 0x00}, + {0x4103, 0x00}, + /* color artifact */ + {0x4243, 0x9A}, + {0x4330, 0x01}, + {0x4331, 0x90}, + {0x4332, 0x02}, + {0x4333, 0x58}, + {0x4334, 0x03}, + {0x4335, 0x20}, + {0x4336, 0x03}, + {0x4337, 0x84}, + {0x433C, 0x01}, + {0x4340, 0x02}, + {0x4341, 0x58}, + {0x4342, 0x03}, + {0x4343, 0x52}, + /* moire reduction */ + {0x4364, 0x0B}, + {0x4368, 0x00}, + {0x4369, 0x0F}, + {0x436A, 0x03}, + {0x436B, 0xA8}, + {0x436C, 0x00}, + {0x436D, 0x00}, + {0x436E, 0x00}, + {0x436F, 0x06}, + /* CNR parameter */ + {0x4281, 0x21}, + {0x4282, 0x18}, + {0x4283, 0x04}, + {0x4284, 0x08}, + {0x4287, 0x7F}, + {0x4288, 0x08}, + {0x428B, 0x7F}, + {0x428C, 0x08}, + {0x428F, 0x7F}, + {0x4297, 0x00}, + {0x4298, 0x7E}, + {0x4299, 0x7E}, + {0x429A, 0x7E}, + {0x42A4, 0xFB}, + {0x42A5, 0x7E}, + {0x42A6, 0xDF}, + {0x42A7, 0xB7}, + {0x42AF, 0x03}, + + /* ARNR Parameter Settings */ + {0x4207, 0x03}, + {0x4216, 0x08}, + {0x4217, 0x08}, + + /* DLC parameter */ + {0x4218, 0x00}, + {0x421B, 0x20}, + {0x421F, 0x04}, + {0x4222, 0x02}, + {0x4223, 0x22}, + {0x422E, 0x54}, + {0x422F, 0xFB}, + {0x4230, 0xFF}, + {0x4231, 0xFE}, + {0x4232, 0xFF}, + {0x4235, 0x58}, + {0x4236, 0xF7}, + {0x4237, 0xFD}, + {0x4239, 0x4E}, + {0x423A, 0xFC}, + {0x423B, 0xFD}, + + /* HDR Setting */ + {0x4300, 0x00}, + {0x4316, 0x12}, + {0x4317, 0x22}, + {0x4318, 0x00}, + {0x4319, 0x00}, + {0x431A, 0x00}, + {0x4324, 0x03}, + {0x4325, 0x20}, + {0x4326, 0x03}, + {0x4327, 0x84}, + {0x4328, 0x03}, + {0x4329, 0x20}, + {0x432A, 0x03}, + {0x432B, 0x20}, + {0x432C, 0x01}, + {0x432D, 0x01}, + {0x4338, 0x02}, + {0x4339, 0x00}, + {0x433A, 0x00}, + {0x433B, 0x02}, + {0x435A, 0x03}, + {0x435B, 0x84}, + {0x435E, 0x01}, + {0x435F, 0xFF}, + {0x4360, 0x01}, + {0x4361, 0xF4}, + {0x4362, 0x03}, + {0x4363, 0x84}, + {0x437B, 0x01}, + {0x4401, 0x3F}, + {0x4402, 0xFF}, + {0x4404, 0x13}, + {0x4405, 0x26}, + {0x4406, 0x07}, + {0x4408, 0x20}, + {0x4409, 0xE5}, + {0x440A, 0xFB}, + {0x440C, 0xF6}, + {0x440D, 0xEA}, + {0x440E, 0x20}, + {0x4410, 0x00}, + {0x4411, 0x00}, + {0x4412, 0x3F}, + {0x4413, 0xFF}, + {0x4414, 0x1F}, + {0x4415, 0xFF}, + {0x4416, 0x20}, + {0x4417, 0x00}, + {0x4418, 0x1F}, + {0x4419, 0xFF}, + {0x441A, 0x20}, + {0x441B, 0x00}, + {0x441D, 0x40}, + {0x441E, 0x1E}, + {0x441F, 0x38}, + {0x4420, 0x01}, + {0x4444, 0x00}, + {0x4445, 0x00}, + {0x4446, 0x1D}, + {0x4447, 0xF9}, + {0x4452, 0x00}, + {0x4453, 0xA0}, + {0x4454, 0x08}, + {0x4455, 0x00}, + {0x4456, 0x0F}, + {0x4457, 0xFF}, + {0x4458, 0x18}, + {0x4459, 0x18}, + {0x445A, 0x3F}, + {0x445B, 0x3A}, + {0x445C, 0x00}, + {0x445D, 0x28}, + {0x445E, 0x01}, + {0x445F, 0x90}, + {0x4460, 0x00}, + {0x4461, 0x60}, + {0x4462, 0x00}, + {0x4463, 0x00}, + {0x4464, 0x00}, + {0x4465, 0x00}, + {0x446C, 0x01}, + {0x446D, 0x00}, + {0x446E, 0x00}, + + /* LSC setting */ + {0x452A, 0x02}, + + /* White balance */ + {0x0712, 0x01}, + {0x0713, 0x00}, + {0x0714, 0x01}, + {0x0715, 0x00}, + {0x0716, 0x01}, + {0x0717, 0x00}, + {0x0718, 0x01}, + {0x0719, 0x00}, + + /* Shading */ + {0x4500, 0x1F}, + + {IMX135_TABLE_WAIT_MS, IMX135_WAIT_MS}, + {IMX135_TABLE_END, 0x00} +}; + +static struct imx135_reg mode_quality[] = { + /* defect correction */ + {0x380A, 0x00}, + {0x380B, 0x00}, + {0x4103, 0x00}, + /* color artifact */ + {0x4243, 0x9A}, + {0x4330, 0x01}, + {0x4331, 0x90}, + {0x4332, 0x02}, + {0x4333, 0x58}, + {0x4334, 0x03}, + {0x4335, 0x20}, + {0x4336, 0x03}, + {0x4337, 0x84}, + {0x433C, 0x01}, + {0x4340, 0x02}, + {0x4341, 0x58}, + {0x4342, 0x03}, + {0x4343, 0x52}, + /* moire reduction */ + {0x4364, 0x0B}, + {0x4368, 0x00}, + {0x4369, 0x0F}, + {0x436A, 0x03}, + {0x436B, 0xA8}, + {0x436C, 0x00}, + {0x436D, 0x00}, + {0x436E, 0x00}, + {0x436F, 0x06}, + /* CNR parameter */ + {0x4281, 0x21}, + {0x4282, 0x18}, + {0x4283, 0x04}, + {0x4284, 0x08}, + {0x4287, 0x7F}, + {0x4288, 0x08}, + {0x428B, 0x7F}, + {0x428C, 0x08}, + {0x428F, 0x7F}, + {0x4297, 0x00}, + {0x4298, 0x7E}, + {0x4299, 0x7E}, + {0x429A, 0x7E}, + {0x42A4, 0xFB}, + {0x42A5, 0x7E}, + {0x42A6, 0xDF}, + {0x42A7, 0xB7}, + {0x42AF, 0x03}, + + /* ARNR Parameter Settings */ + {0x4207, 0x03}, + {0x4216, 0x08}, + {0x4217, 0x08}, + + /* DLC parameter */ + {0x4218, 0x00}, + {0x421B, 0x20}, + {0x421F, 0x04}, + {0x4222, 0x02}, + {0x4223, 0x22}, + {0x422E, 0x54}, + {0x422F, 0xFB}, + {0x4230, 0xFF}, + {0x4231, 0xFE}, + {0x4232, 0xFF}, + {0x4235, 0x58}, + {0x4236, 0xF7}, + {0x4237, 0xFD}, + {0x4239, 0x4E}, + {0x423A, 0xFC}, + {0x423B, 0xFD}, + + /* HDR Setting */ + {0x4300, 0x00}, + {0x4316, 0x12}, + {0x4317, 0x22}, + {0x4318, 0x00}, + {0x4319, 0x00}, + {0x431A, 0x00}, + {0x4324, 0x03}, + {0x4325, 0x20}, + {0x4326, 0x03}, + {0x4327, 0x84}, + {0x4328, 0x03}, + {0x4329, 0x20}, + {0x432A, 0x03}, + {0x432B, 0x20}, + {0x432C, 0x01}, + {0x432D, 0x01}, + {0x4338, 0x02}, + {0x4339, 0x00}, + {0x433A, 0x00}, + {0x433B, 0x02}, + {0x435A, 0x03}, + {0x435B, 0x84}, + {0x435E, 0x01}, + {0x435F, 0xFF}, + {0x4360, 0x01}, + {0x4361, 0xF4}, + {0x4362, 0x03}, + {0x4363, 0x84}, + {0x437B, 0x01}, + {0x4401, 0x3F}, + {0x4402, 0xFF}, + {0x4404, 0x13}, + {0x4405, 0x26}, + {0x4406, 0x07}, + {0x4408, 0x20}, + {0x4409, 0xE5}, + {0x440A, 0xFB}, + {0x440C, 0xF6}, + {0x440D, 0xEA}, + {0x440E, 0x20}, + {0x4410, 0x00}, + {0x4411, 0x00}, + {0x4412, 0x3F}, + {0x4413, 0xFF}, + {0x4414, 0x1F}, + {0x4415, 0xFF}, + {0x4416, 0x20}, + {0x4417, 0x00}, + {0x4418, 0x1F}, + {0x4419, 0xFF}, + {0x441A, 0x20}, + {0x441B, 0x00}, + {0x441D, 0x40}, + {0x441E, 0x1E}, + {0x441F, 0x38}, + {0x4420, 0x01}, + {0x4444, 0x00}, + {0x4445, 0x00}, + {0x4446, 0x1D}, + {0x4447, 0xF9}, + {0x4452, 0x00}, + {0x4453, 0xA0}, + {0x4454, 0x08}, + {0x4455, 0x00}, + {0x4456, 0x0F}, + {0x4457, 0xFF}, + {0x4458, 0x18}, + {0x4459, 0x18}, + {0x445A, 0x3F}, + {0x445B, 0x3A}, + {0x445C, 0x00}, + {0x445D, 0x28}, + {0x445E, 0x01}, + {0x445F, 0x90}, + {0x4460, 0x00}, + {0x4461, 0x60}, + {0x4462, 0x00}, + {0x4463, 0x00}, + {0x4464, 0x00}, + {0x4465, 0x00}, + {0x446C, 0x01}, + {0x446D, 0x00}, + {0x446E, 0x00}, + + /* LSC setting */ + {0x452A, 0x02}, + + /* White balance */ + {0x0712, 0x01}, + {0x0713, 0x00}, + {0x0714, 0x01}, + {0x0715, 0x00}, + {0x0716, 0x01}, + {0x0717, 0x00}, + {0x0718, 0x01}, + {0x0719, 0x00}, + + /* Shading */ + {0x4500, 0x1F}, + + {IMX135_TABLE_WAIT_MS, IMX135_WAIT_MS}, + {IMX135_TABLE_END, 0x00} +}; + +enum { + IMX135_MODE_4208X3120, + IMX135_MODE_1920X1080, + IMX135_MODE_1280X720, + IMX135_MODE_2616X1472, + IMX135_MODE_3896X2192, + IMX135_MODE_QUALITY_HDR, + IMX135_MODE_QUALITY, +}; + +static struct imx135_reg *mode_table[] = { + [IMX135_MODE_4208X3120] = mode_4208x3120, + [IMX135_MODE_1920X1080] = mode_1920x1080, + [IMX135_MODE_1280X720] = mode_1280x720, + [IMX135_MODE_2616X1472] = mode_2616x1472, + [IMX135_MODE_3896X2192] = mode_3896x2192, + [IMX135_MODE_QUALITY_HDR] = mode_quality_hdr, + [IMX135_MODE_QUALITY] = mode_quality, +}; + +static inline void +msleep_range(unsigned int delay_base) +{ + usleep_range(delay_base*1000, delay_base*1000+500); +} + +static inline void +imx135_get_frame_length_regs(struct imx135_reg *regs, u32 frame_length) +{ + regs->addr = 0x0340; + regs->val = (frame_length >> 8) & 0xff; + (regs + 1)->addr = 0x0341; + (regs + 1)->val = (frame_length) & 0xff; +} + +static inline void +imx135_get_coarse_time_regs(struct imx135_reg *regs, u32 coarse_time) +{ + regs->addr = 0x202; + regs->val = (coarse_time >> 8) & 0xff; + (regs + 1)->addr = 0x203; + (regs + 1)->val = (coarse_time) & 0xff; +} + +static inline void +imx135_get_coarse_time_short_regs(struct imx135_reg *regs, u32 coarse_time) +{ + regs->addr = 0x230; + regs->val = (coarse_time >> 8) & 0xff; + (regs + 1)->addr = 0x231; + (regs + 1)->val = (coarse_time) & 0xff; +} + +static inline void +imx135_get_gain_reg(struct imx135_reg *regs, u16 gain) +{ + regs->addr = 0x205; + regs->val = gain; +} + +static int +imx135_read_reg(struct i2c_client *client, u16 addr, u8 *val) +{ + int err; + struct i2c_msg msg[2]; + unsigned char data[3]; + + if (!client->adapter) + return -ENODEV; + + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = 2; + msg[0].buf = data; + + /* high byte goes out first */ + data[0] = (u8) (addr >> 8); + data[1] = (u8) (addr & 0xff); + + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = 1; + msg[1].buf = data + 2; + + err = i2c_transfer(client->adapter, msg, 2); + + if (err != 2) + return -EINVAL; + + *val = data[2]; + return 0; +} + +static int +imx135_write_reg(struct i2c_client *client, u16 addr, u8 val) +{ + int err; + struct i2c_msg msg; + unsigned char data[3]; + + if (!client->adapter) + return -ENODEV; + + data[0] = (u8) (addr >> 8); + data[1] = (u8) (addr & 0xff); + data[2] = (u8) (val & 0xff); + + msg.addr = client->addr; + msg.flags = 0; + msg.len = 3; + msg.buf = data; + + err = i2c_transfer(client->adapter, &msg, 1); + if (err == 1) + return 0; + + pr_err("%s:i2c write failed, %x = %x\n", + __func__, addr, val); + + return err; +} + +static int +imx135_write_table(struct i2c_client *client, + const struct imx135_reg table[], + const struct imx135_reg override_list[], + int num_override_regs) +{ + int err; + const struct imx135_reg *next; + int i; + u16 val; + + for (next = table; next->addr != IMX135_TABLE_END; next++) { + if (next->addr == IMX135_TABLE_WAIT_MS) { + msleep_range(next->val); + continue; + } + + val = next->val; + + /* When an override list is passed in, replace the reg */ + /* value to write if the reg is in the list */ + if (override_list) { + for (i = 0; i < num_override_regs; i++) { + if (next->addr == override_list[i].addr) { + val = override_list[i].val; + break; + } + } + } + + err = imx135_write_reg(client, next->addr, val); + if (err) { + pr_err("%s:imx135_write_table:%d", __func__, err); + return err; + } + } + return 0; +} + +static int +imx135_set_mode(struct imx135_info *info, struct imx135_mode *mode) +{ + int sensor_mode; + u8 quality_hdr; + int err; + struct imx135_reg reg_list[8]; + + pr_info("%s: xres %u yres %u framelength %u coarsetime %u gain %u, hdr %d\n", + __func__, mode->xres, mode->yres, mode->frame_length, + mode->coarse_time, mode->gain, mode->hdr_en); + + if (mode->xres == 4208 && mode->yres == 3120) { + sensor_mode = IMX135_MODE_4208X3120; + quality_hdr = 1; + } else if (mode->xres == 1920 && mode->yres == 1080) { + sensor_mode = IMX135_MODE_1920X1080; + quality_hdr = 0; + } else if (mode->xres == 1280 && mode->yres == 720) { + sensor_mode = IMX135_MODE_1280X720; + quality_hdr = 0; + } else if (mode->xres == 2616 && mode->yres == 1472) { + sensor_mode = IMX135_MODE_2616X1472; + quality_hdr = 1; + } else if (mode->xres == 3896 && mode->yres == 2192) { + sensor_mode = IMX135_MODE_3896X2192; + quality_hdr = 1; + } else { + pr_err("%s: invalid resolution supplied to set mode %d %d\n", + __func__, mode->xres, mode->yres); + return -EINVAL; + } + + /* get a list of override regs for the asking frame length, */ + /* coarse integration time, and gain. */ + imx135_get_frame_length_regs(reg_list, mode->frame_length); + imx135_get_coarse_time_regs(reg_list + 2, mode->coarse_time); + imx135_get_gain_reg(reg_list + 4, mode->gain); + if (mode->hdr_en == 1) /* if HDR is enabled */ + imx135_get_coarse_time_short_regs( + reg_list + 6, mode->coarse_time_short); + + err = imx135_write_table(info->i2c_client, + mode_table[sensor_mode], + reg_list, mode->hdr_en ? 7 : 5); + if (err) + return err; + if (quality_hdr) + err = imx135_write_table(info->i2c_client, + mode_table[IMX135_MODE_QUALITY_HDR], + reg_list, 0); + else + err = imx135_write_table(info->i2c_client, + mode_table[IMX135_MODE_QUALITY], + reg_list, 0); + if (err) + return err; + + info->mode = sensor_mode; + pr_info("[IMX135]: stream on.\n"); + return 0; +} + +static int +imx135_get_status(struct imx135_info *info, u8 *dev_status) +{ + *dev_status = 0; + return 0; +} + +static int +imx135_set_frame_length(struct imx135_info *info, u32 frame_length, + bool group_hold) +{ + struct imx135_reg reg_list[2]; + int i = 0; + int ret; + + imx135_get_frame_length_regs(reg_list, frame_length); + + if (group_hold) { + ret = imx135_write_reg(info->i2c_client, 0x0104, 0x01); + if (ret) + return ret; + } + + for (i = 0; i < 2; i++) { + ret = imx135_write_reg(info->i2c_client, reg_list[i].addr, + reg_list[i].val); + if (ret) + return ret; + } + + if (group_hold) { + ret = imx135_write_reg(info->i2c_client, 0x0104, 0x0); + if (ret) + return ret; + } + + return 0; +} + +static int +imx135_set_coarse_time(struct imx135_info *info, u32 coarse_time, + bool group_hold) +{ + int ret; + + struct imx135_reg reg_list[2]; + int i = 0; + + imx135_get_coarse_time_regs(reg_list, coarse_time); + + if (group_hold) { + ret = imx135_write_reg(info->i2c_client, 0x104, 0x01); + if (ret) + return ret; + } + + for (i = 0; i < 2; i++) { + ret = imx135_write_reg(info->i2c_client, reg_list[i].addr, + reg_list[i].val); + if (ret) + return ret; + } + + if (group_hold) { + ret = imx135_write_reg(info->i2c_client, 0x104, 0x0); + if (ret) + return ret; + } + return 0; +} + +static int +imx135_set_gain(struct imx135_info *info, u16 gain, bool group_hold) +{ + int ret; + struct imx135_reg reg_list; + + imx135_get_gain_reg(®_list, gain); + + if (group_hold) { + ret = imx135_write_reg(info->i2c_client, 0x104, 0x1); + if (ret) + return ret; + } + + ret = imx135_write_reg(info->i2c_client, reg_list.addr, reg_list.val); + /* writing second gain register for HDR */ + ret = imx135_write_reg(info->i2c_client, 0x233, reg_list.val); + if (ret) + return ret; + + if (group_hold) { + ret = imx135_write_reg(info->i2c_client, 0x104, 0x0); + if (ret) + return ret; + } + return 0; +} + +static int +imx135_set_hdr_coarse_time(struct imx135_info *info, struct imx135_hdr *values) +{ + struct imx135_reg reg_list[2]; + struct imx135_reg reg_list_short[2]; + int ret, i = 0; + + /* get long and short coarse time registers */ + imx135_get_coarse_time_regs(reg_list, values->coarse_time_long); + imx135_get_coarse_time_short_regs(reg_list_short, + values->coarse_time_short); + /* set to direct mode */ + ret = imx135_write_reg(info->i2c_client, 0x238, 0x1); + if (ret) + return ret; + /* set group hold */ + ret = imx135_write_reg(info->i2c_client, 0x104, 0x1); + if (ret) + return ret; + /* writing long exposure */ + for (i = 0; i < 2; i++) { + ret = imx135_write_reg(info->i2c_client, reg_list[i].addr, + reg_list[i].val); + if (ret) + return ret; + } + /* writing short exposure */ + for (i = 0; i < 2; i++) { + ret = imx135_write_reg(info->i2c_client, reg_list_short[i].addr, + reg_list_short[i].val); + if (ret) + return ret; + } + ret = imx135_write_reg(info->i2c_client, 0x104, 0x0); + if (ret) + return ret; + + return 0; +} + +static int +imx135_set_group_hold(struct imx135_info *info, struct imx135_ae *ae) +{ + int ret; + int count = 0; + bool groupHoldEnabled = false; + + if (ae->gain_enable) + count++; + if (ae->coarse_time_enable) + count++; + if (ae->frame_length_enable) + count++; + if (count >= 2) + groupHoldEnabled = true; + + if (groupHoldEnabled) { + ret = imx135_write_reg(info->i2c_client, 0x104, 0x1); + if (ret) + return ret; + } + + if (ae->gain_enable) + imx135_set_gain(info, ae->gain, false); + if (ae->coarse_time_enable) + imx135_set_coarse_time(info, ae->coarse_time, false); + if (ae->frame_length_enable) + imx135_set_frame_length(info, ae->frame_length, false); + + if (groupHoldEnabled) { + ret = imx135_write_reg(info->i2c_client, 0x104, 0x0); + if (ret) + return ret; + } + + return 0; +} + +static int imx135_get_sensor_id(struct imx135_info *info) +{ + int ret = 0; + int i; + u8 bak = 0; + + pr_info("%s\n", __func__); + if (info->sensor_data.fuse_id_size) + return 0; + + /* Note 1: If the sensor does not have power at this point + Need to supply the power, e.g. by calling power on function */ + + ret |= imx135_write_reg(info->i2c_client, 0x3B02, 0x00); + ret |= imx135_write_reg(info->i2c_client, 0x3B00, 0x01); + for (i = 0; i < 9 ; i++) { + ret |= imx135_read_reg(info->i2c_client, 0x3B24 + i, &bak); + info->sensor_data.fuse_id[i] = bak; + } + + if (!ret) + info->sensor_data.fuse_id_size = i; + + /* Note 2: Need to clean up any action carried out in Note 1 */ + + return ret; +} + +static long +imx135_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + int err; + struct imx135_info *info = file->private_data; + + switch (cmd) { + case IMX135_IOCTL_SET_MODE: + { + struct imx135_mode mode; + if (copy_from_user(&mode, (const void __user *)arg, + sizeof(struct imx135_mode))) { + pr_err("%s:Failed to get mode from user.\n", __func__); + return -EFAULT; + } + return imx135_set_mode(info, &mode); + } + case IMX135_IOCTL_SET_FRAME_LENGTH: + return imx135_set_frame_length(info, (u32)arg, true); + case IMX135_IOCTL_SET_COARSE_TIME: + return imx135_set_coarse_time(info, (u32)arg, true); + case IMX135_IOCTL_SET_GAIN: + return imx135_set_gain(info, (u16)arg, true); + case IMX135_IOCTL_GET_STATUS: + { + u8 status; + + err = imx135_get_status(info, &status); + if (err) + return err; + if (copy_to_user((void __user *)arg, &status, 1)) { + pr_err("%s:Failed to copy status to user\n", __func__); + return -EFAULT; + } + return 0; + } + case IMX135_IOCTL_GET_SENSORDATA: + { + err = imx135_get_sensor_id(info); + + if (err) { + pr_err("%s:Failed to get fuse id info.\n", __func__); + return err; + } + if (copy_to_user((void __user *)arg, &info->sensor_data, + sizeof(struct imx135_sensordata))) { + pr_info("%s:Failed to copy fuse id to user space\n", + __func__); + return -EFAULT; + } + return 0; + } + case IMX135_IOCTL_SET_GROUP_HOLD: + { + struct imx135_ae ae; + if (copy_from_user(&ae, (const void __user *)arg, + sizeof(struct imx135_ae))) { + pr_info("%s:fail group hold\n", __func__); + return -EFAULT; + } + return imx135_set_group_hold(info, &ae); + } + case IMX135_IOCTL_SET_HDR_COARSE_TIME: + { + struct imx135_hdr values; + + dev_dbg(&info->i2c_client->dev, + "IMX135_IOCTL_SET_HDR_COARSE_TIME\n"); + if (copy_from_user(&values, + (const void __user *)arg, + sizeof(struct imx135_hdr))) { + err = -EFAULT; + break; + } + err = imx135_set_hdr_coarse_time(info, &values); + break; + } + default: + pr_err("%s:unknown cmd.\n", __func__); + return -EINVAL; + } + return 0; +} + +static int imx135_debugfs_show(struct seq_file *s, void *unused) +{ + struct imx135_info *dev = s->private; + + dev_dbg(&dev->i2c_client->dev, "%s: ++\n", __func__); + + mutex_lock(&dev->imx135_camera_lock); + mutex_unlock(&dev->imx135_camera_lock); + + return 0; +} + +static ssize_t imx135_debugfs_write( + struct file *file, + char const __user *buf, + size_t count, + loff_t *offset) +{ + struct imx135_info *dev = + ((struct seq_file *)file->private_data)->private; + struct i2c_client *i2c_client = dev->i2c_client; + int ret = 0; + char buffer[24]; + u32 address; + u32 data; + u8 readback; + + dev_dbg(&i2c_client->dev, "%s: ++\n", __func__); + + if (copy_from_user(&buffer, buf, sizeof(buffer))) + goto debugfs_write_fail; + + if (sscanf(buf, "0x%x 0x%x", &address, &data) == 2) + goto set_attr; + if (sscanf(buf, "0X%x 0X%x", &address, &data) == 2) + goto set_attr; + if (sscanf(buf, "%d %d", &address, &data) == 2) + goto set_attr; + + if (sscanf(buf, "0x%x 0x%x", &address, &data) == 1) + goto read; + if (sscanf(buf, "0X%x 0X%x", &address, &data) == 1) + goto read; + if (sscanf(buf, "%d %d", &address, &data) == 1) + goto read; + + dev_err(&i2c_client->dev, "SYNTAX ERROR: %s\n", buf); + return -EFAULT; + +set_attr: + dev_info(&i2c_client->dev, + "new address = %x, data = %x\n", address, data); + ret |= imx135_write_reg(i2c_client, address, data); +read: + ret |= imx135_read_reg(i2c_client, address, &readback); + dev_dbg(&i2c_client->dev, + "wrote to address 0x%x with value 0x%x\n", + address, readback); + + if (ret) + goto debugfs_write_fail; + + return count; + +debugfs_write_fail: + dev_err(&i2c_client->dev, + "%s: test pattern write failed\n", __func__); + return -EFAULT; +} + +static int imx135_debugfs_open(struct inode *inode, struct file *file) +{ + struct imx135_info *dev = inode->i_private; + struct i2c_client *i2c_client = dev->i2c_client; + + dev_dbg(&i2c_client->dev, "%s: ++\n", __func__); + + return single_open(file, imx135_debugfs_show, inode->i_private); +} + +static const struct file_operations imx135_debugfs_fops = { + .open = imx135_debugfs_open, + .read = seq_read, + .write = imx135_debugfs_write, + .llseek = seq_lseek, + .release = single_release, +}; + +static void imx135_remove_debugfs(struct imx135_info *dev) +{ + struct i2c_client *i2c_client = dev->i2c_client; + + dev_dbg(&i2c_client->dev, "%s: ++\n", __func__); + + if (dev->debugdir) + debugfs_remove_recursive(dev->debugdir); + dev->debugdir = NULL; +} + +static void imx135_create_debugfs(struct imx135_info *dev) +{ + struct dentry *ret; + struct i2c_client *i2c_client = dev->i2c_client; + + dev_dbg(&i2c_client->dev, "%s\n", __func__); + + dev->debugdir = + debugfs_create_dir(dev->miscdev_info.this_device->kobj.name, + NULL); + if (!dev->debugdir) + goto remove_debugfs; + + ret = debugfs_create_file("d", + S_IWUSR | S_IRUGO, + dev->debugdir, dev, + &imx135_debugfs_fops); + if (!ret) + goto remove_debugfs; + + return; +remove_debugfs: + dev_err(&i2c_client->dev, "couldn't create debugfs\n"); + imx135_remove_debugfs(dev); +} + +static int +imx135_open(struct inode *inode, struct file *file) +{ + struct miscdevice *miscdev = file->private_data; + struct imx135_info *info; + + info = container_of(miscdev, struct imx135_info, miscdev_info); + /* check if the device is in use */ + if (atomic_xchg(&info->in_use, 1)) { + pr_info("%s:BUSY!\n", __func__); + return -EBUSY; + } + + file->private_data = info; + + if (info->pdata && info->pdata->power_on) + info->pdata->power_on(&info->power); + else{ + pr_err("%s:no valid power_on function.\n", __func__); + return -EEXIST; + } + + return 0; +} + +static int +imx135_release(struct inode *inode, struct file *file) +{ + struct imx135_info *info = file->private_data; + + if (info->pdata && info->pdata->power_off) + info->pdata->power_off(&info->power); + file->private_data = NULL; + + /* warn if device is already released */ + WARN_ON(!atomic_xchg(&info->in_use, 0)); + return 0; +} + +static int imx135_power_put(struct imx135_power_rail *pw) +{ + if (unlikely(!pw)) + return -EFAULT; + + if (likely(pw->avdd)) + regulator_put(pw->avdd); + + if (likely(pw->iovdd)) + regulator_put(pw->iovdd); + + if (likely(pw->dvdd)) + regulator_put(pw->dvdd); + + pw->avdd = NULL; + pw->iovdd = NULL; + pw->dvdd = NULL; + + return 0; +} + +static int imx135_regulator_get(struct imx135_info *info, + struct regulator **vreg, char vreg_name[]) +{ + struct regulator *reg = NULL; + int err = 0; + + reg = regulator_get(&info->i2c_client->dev, vreg_name); + if (unlikely(IS_ERR_OR_NULL(reg))) { + dev_err(&info->i2c_client->dev, "%s %s ERR: %d\n", + __func__, vreg_name, (int)reg); + err = PTR_ERR(reg); + reg = NULL; + } else + dev_dbg(&info->i2c_client->dev, "%s: %s\n", + __func__, vreg_name); + + *vreg = reg; + return err; +} + +static int imx135_power_get(struct imx135_info *info) +{ + struct imx135_power_rail *pw = &info->power; + + imx135_regulator_get(info, &pw->avdd, "vana"); /* ananlog 2.7v */ + imx135_regulator_get(info, &pw->dvdd, "vdig"); /* digital 1.2v */ + imx135_regulator_get(info, &pw->iovdd, "vif"); /* interface 1.8v */ + + return 0; +} + +static const struct file_operations imx135_fileops = { + .owner = THIS_MODULE, + .open = imx135_open, + .unlocked_ioctl = imx135_ioctl, + .release = imx135_release, +}; + +static struct miscdevice imx135_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "imx135", + .fops = &imx135_fileops, +}; + + +static int +imx135_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct imx135_info *info; + int err; + + pr_info("[IMX135]: probing sensor.\n"); + + info = devm_kzalloc(&client->dev, + sizeof(struct imx135_info), GFP_KERNEL); + if (!info) { + pr_err("%s:Unable to allocate memory!\n", __func__); + return -ENOMEM; + } + + info->pdata = client->dev.platform_data; + info->i2c_client = client; + atomic_set(&info->in_use, 0); + info->mode = -1; + + imx135_power_get(info); + + memcpy(&info->miscdev_info, + &imx135_device, + sizeof(struct miscdevice)); + + err = misc_register(&info->miscdev_info); + if (err) { + pr_err("%s:Unable to register misc device!\n", __func__); + goto imx135_probe_fail; + } + + i2c_set_clientdata(client, info); + /* create debugfs interface */ + imx135_create_debugfs(info); + return 0; + +imx135_probe_fail: + imx135_power_put(&info->power); + + return err; +} + +static int +imx135_remove(struct i2c_client *client) +{ + struct imx135_info *info; + info = i2c_get_clientdata(client); + misc_deregister(&imx135_device); + + imx135_power_put(&info->power); + + imx135_remove_debugfs(info); + return 0; +} + +static const struct i2c_device_id imx135_id[] = { + { "imx135", 0 }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, imx135_id); + +static struct i2c_driver imx135_i2c_driver = { + .driver = { + .name = "imx135", + .owner = THIS_MODULE, + }, + .probe = imx135_probe, + .remove = imx135_remove, + .id_table = imx135_id, +}; + +static int __init imx135_init(void) +{ + pr_info("[IMX135] sensor driver loading\n"); + return i2c_add_driver(&imx135_i2c_driver); +} + +static void __exit imx135_exit(void) +{ + i2c_del_driver(&imx135_i2c_driver); +} + +module_init(imx135_init); +module_exit(imx135_exit); -- cgit v1.2.3