diff options
| author | Jake Day <jake@ninebysix.com> | 2020-09-25 10:23:58 -0400 |
|---|---|---|
| committer | Kieran Bingham <kieran.bingham+renesas@ideasonboard.com> | 2020-10-14 10:51:58 +0100 |
| commit | d2606552ddb7871f0dd703f3655dec6bd7482407 (patch) | |
| tree | 9c5bfddfc366dfafde3ebd30dc8f3fcc29786f60 | |
| parent | 3a9c7f29a5024d2526266835f5b4d56747e133e0 (diff) | |
| download | rcar-d2606552ddb7871f0dd703f3655dec6bd7482407.tar.gz | |
imx135 camera sensor drivervsp1/pa-phase
| -rw-r--r-- | drivers/media/i2c/Kconfig | 13 | ||||
| -rw-r--r-- | drivers/media/i2c/Makefile | 1 | ||||
| -rw-r--r-- | drivers/media/i2c/imx135.c | 1482 |
3 files changed, 1496 insertions, 0 deletions
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 878f66ef2719f..5bead52f9ebae 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -738,6 +738,19 @@ config VIDEO_HI556 To compile this driver as a module, choose M here: the module will be called hi556. +config VIDEO_IMX135 + tristate "Sony IMX135 sensor support" + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API + select V4L2_FWNODE + help + This is a Video4Linux2 sensor driver for the Sony + IMX135 camera. + + To compile this driver as a module, choose M here: the + module will be called imx135. + config VIDEO_IMX214 tristate "Sony IMX214 sensor support" depends on GPIOLIB && I2C && VIDEO_V4L2 diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index f0a77473979d8..a1092ea4ed9a1 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -112,6 +112,7 @@ obj-$(CONFIG_VIDEO_ML86V7667) += ml86v7667.o obj-$(CONFIG_VIDEO_OV2659) += ov2659.o obj-$(CONFIG_VIDEO_TC358743) += tc358743.o obj-$(CONFIG_VIDEO_HI556) += hi556.o +obj-$(CONFIG_VIDEO_IMX135) += imx135.o obj-$(CONFIG_VIDEO_IMX214) += imx214.o obj-$(CONFIG_VIDEO_IMX219) += imx219.o obj-$(CONFIG_VIDEO_IMX258) += imx258.o diff --git a/drivers/media/i2c/imx135.c b/drivers/media/i2c/imx135.c new file mode 100644 index 0000000000000..79d0b1fd317e8 --- /dev/null +++ b/drivers/media/i2c/imx135.c @@ -0,0 +1,1482 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Sony IMX135 CMOS Image Sensor Driver + * + * Author: Jake Day <jake@ninebysix.com> + */ + +#include <linux/acpi.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/input.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/types.h> +#include <media/media-entity.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> +#include <media/v4l2-subdev.h> + +#define IMX135_STANDBY 0x0100 +#define IMX135_REGHOLD 0x0104 +#define IMX135_XMSTA 0x0100 +#define IMX135_GAIN 0x0205 + +#define IMX135_DEFAULT_LINK_FREQ 451200000 + +#define IMX135_TABLE_WAIT_MS 0 +#define IMX135_TABLE_END 1 +#define IMX135_MAX_RETRIES 3 +#define IMX135_WAIT_MS 3 + +static const char * const imx135_supply_name[] = { + "vana", /* analog 2.7v */ + "vdig", /* digital 1.05v */ + "vif" /* IO 1.8v */ +}; + +#define IMX135_NUM_SUPPLIES ARRAY_SIZE(imx135_supply_name) + +struct imx135_regval { + u16 reg; + u8 val; +}; + +struct imx135_mode { + u32 width; + u32 height; + u32 pixel_rate; + u32 link_freq_index; + + const struct imx135_regval *data; + u32 data_size; +}; + +struct imx135 { + struct device *dev; + struct clk *xclk; + struct regmap *regmap; + + struct v4l2_subdev sd; + struct media_pad pad; + struct v4l2_mbus_framefmt current_format; + const struct imx135_mode *current_mode; + + struct regulator_bulk_data supplies[IMX135_NUM_SUPPLIES]; + struct gpio_desc *rst_gpio; + + struct v4l2_ctrl_handler ctrls; + struct v4l2_ctrl *link_freq; + struct v4l2_ctrl *pixel_rate; + + struct mutex lock; +}; + +struct imx135_pixfmt { + u32 code; +}; + +static const struct imx135_pixfmt imx135_formats[] = { + { MEDIA_BUS_FMT_SRGGB10_1X10 }, +}; + +static const struct regmap_config imx135_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, +}; + +static const struct imx135_regval imx135_global_init_settings[] = { + /* software reset */ + {0x0103, 0x01}, + /* Clock Setting */ + {0x011E, 0x18}, + {0x011F, 0x00}, + {0x0301, 0x05}, + {0x0303, 0x01}, + {0x0305, 0x0C}, + {0x0309, 0x05}, + {0x030B, 0x02}, + {0x030C, 0x01}, + {0x030D, 0xC2}, + {0x030E, 0x01}, + {0x3A06, 0x12}, + /* 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}, + /* 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} +}; + +static struct imx135_regval imx135_3120p_settings[] = { + /* 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} +}; + +static struct imx135_regval imx135_2192p_settings[] = { + /* 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_regval imx135_1472p_settings[] = { + /* 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 const struct imx135_regval imx135_1080p_settings[] = { + /* 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}, + /* 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} +}; + +static const struct imx135_regval imx135_720p_settings[] = { + /* 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}, + /* 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} +}; + +static const struct imx135_regval imx135_10bit_settings[] = { + /* 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} +}; + +/* supported link frequencies */ +static const s64 imx135_link_freq[] = { + IMX135_DEFAULT_LINK_FREQ, +}; + +/* Mode configs */ +static const struct imx135_mode imx135_modes[] = { + { + .width = 4208, + .height = 3120, + .data = imx135_3120p_settings, + .data_size = ARRAY_SIZE(imx135_3120p_settings), + .pixel_rate = 360960000, + .link_freq_index = 0, + }, + { + .width = 3896, + .height = 2192, + .data = imx135_2192p_settings, + .data_size = ARRAY_SIZE(imx135_2192p_settings), + .pixel_rate = 360960000, + .link_freq_index = 0, + }, + { + .width = 2616, + .height = 1472, + .data = imx135_1472p_settings, + .data_size = ARRAY_SIZE(imx135_1472p_settings), + .pixel_rate = 360960000, + .link_freq_index = 0, + }, + { + .width = 1920, + .height = 1080, + .data = imx135_1080p_settings, + .data_size = ARRAY_SIZE(imx135_1080p_settings), + .pixel_rate = 360960000, + .link_freq_index = 0, + }, + { + .width = 1280, + .height = 720, + .data = imx135_720p_settings, + .data_size = ARRAY_SIZE(imx135_720p_settings), + .pixel_rate = 360960000, + .link_freq_index = 0, + }, +}; + +static inline struct imx135 *to_imx135(struct v4l2_subdev *_sd) +{ + return container_of(_sd, struct imx135, sd); +} + +static inline int imx135_read_reg(struct imx135 *imx135, u16 addr, u8 *value) +{ + unsigned int regval; + int ret; + + ret = regmap_read(imx135->regmap, addr, ®val); + if (ret) { + dev_err(imx135->dev, "I2C read failed for addr: %x\n", addr); + return ret; + } + + *value = regval & 0xff; + + return 0; +} + +static int imx135_write_reg(struct imx135 *imx135, u16 addr, u8 value) +{ + int ret; + + ret = regmap_write(imx135->regmap, addr, value); + if (ret) { + dev_err(imx135->dev, "I2C write failed for addr: %x\n", addr); + return ret; + } + + return ret; +} + +static int imx135_set_register_array(struct imx135 *imx135, + const struct imx135_regval *settings, + unsigned int num_settings) +{ + unsigned int i; + int ret; + + for (i = 0; i < num_settings; ++i, ++settings) { + ret = imx135_write_reg(imx135, settings->reg, settings->val); + if (ret < 0) + return ret; + + /* Settle time is 10ms for all registers */ + msleep(10); + } + + return 0; +} + +static int imx135_write_buffered_reg(struct imx135 *imx135, u16 address_low, + u8 nr_regs, u32 value) +{ + unsigned int i; + int ret; + + ret = imx135_write_reg(imx135, IMX135_REGHOLD, 0x01); + if (ret) { + dev_err(imx135->dev, "Error setting hold register\n"); + return ret; + } + + for (i = 0; i < nr_regs; i++) { + ret = imx135_write_reg(imx135, address_low + i, + (u8)(value >> (i * 8))); + if (ret) { + dev_err(imx135->dev, "Error writing buffered registers\n"); + return ret; + } + } + + ret = imx135_write_reg(imx135, IMX135_REGHOLD, 0x00); + if (ret) { + dev_err(imx135->dev, "Error setting hold register\n"); + return ret; + } + + return ret; +} + +static int imx135_set_gain(struct imx135 *imx135, u32 value) +{ + int ret; + + ret = imx135_write_buffered_reg(imx135, IMX135_GAIN, 1, value); + if (ret) + dev_err(imx135->dev, "Unable to write gain\n"); + + return ret; +} + +/* Stop streaming */ +static int imx135_stop_streaming(struct imx135 *imx135) +{ + int ret; + + ret = imx135_write_reg(imx135, IMX135_STANDBY, 0x01); + if (ret < 0) + return ret; + + msleep(30); + + return imx135_write_reg(imx135, IMX135_XMSTA, 0x01); +} + +static int imx135_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct imx135 *imx135 = container_of(ctrl->handler, + struct imx135, ctrls); + int ret = 0; + + /* V4L2 controls values will be applied only when power is already up */ + if (!pm_runtime_get_if_in_use(imx135->dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_GAIN: + ret = imx135_set_gain(imx135, ctrl->val); + break; + default: + ret = -EINVAL; + break; + } + + pm_runtime_put(imx135->dev); + + return ret; +} + +static const struct v4l2_ctrl_ops imx135_ctrl_ops = { + .s_ctrl = imx135_set_ctrl, +}; + +static int imx135_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index >= ARRAY_SIZE(imx135_formats)) + return -EINVAL; + + code->code = imx135_formats[code->index].code; + + return 0; +} + +static int imx135_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct imx135 *imx135 = to_imx135(sd); + struct v4l2_mbus_framefmt *framefmt; + + mutex_lock(&imx135->lock); + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) + framefmt = v4l2_subdev_get_try_format(&imx135->sd, cfg, + fmt->pad); + else + framefmt = &imx135->current_format; + + fmt->format = *framefmt; + + mutex_unlock(&imx135->lock); + + return 0; +} + +static int imx135_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct imx135 *imx135 = to_imx135(sd); + const struct imx135_mode *mode; + struct v4l2_mbus_framefmt *format; + unsigned int i; + + mutex_lock(&imx135->lock); + + mode = v4l2_find_nearest_size(imx135_modes, + ARRAY_SIZE(imx135_modes), + width, height, + fmt->format.width, fmt->format.height); + + fmt->format.width = mode->width; + fmt->format.height = mode->height; + + for (i = 0; i < ARRAY_SIZE(imx135_formats); i++) + if (imx135_formats[i].code == fmt->format.code) + break; + + if (i >= ARRAY_SIZE(imx135_formats)) + i = 0; + + fmt->format.code = imx135_formats[i].code; + fmt->format.field = V4L2_FIELD_NONE; + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + format = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); + } else { + format = &imx135->current_format; + __v4l2_ctrl_s_ctrl(imx135->link_freq, mode->link_freq_index); + __v4l2_ctrl_s_ctrl_int64(imx135->pixel_rate, mode->pixel_rate); + + imx135->current_mode = mode; + } + + *format = fmt->format; + + mutex_unlock(&imx135->lock); + + return 0; +} + +static int imx135_entity_init_cfg(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *cfg) +{ + struct v4l2_subdev_format fmt = { 0 }; + + fmt.which = cfg ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; + fmt.format.width = 1920; + fmt.format.height = 1080; + + imx135_set_fmt(subdev, cfg, &fmt); + + return 0; +} + +static int imx135_write_current_format(struct imx135 *imx135, + struct v4l2_mbus_framefmt *format) +{ + int ret; + + switch (format->code) { + case MEDIA_BUS_FMT_SRGGB10_1X10: + ret = imx135_set_register_array(imx135, imx135_10bit_settings, + ARRAY_SIZE( + imx135_10bit_settings)); + if (ret < 0) { + dev_err(imx135->dev, "Could not set format registers\n"); + return ret; + } + break; + default: + dev_err(imx135->dev, "Unknown pixel format\n"); + return -EINVAL; + } + + return 0; +} + +/* Start streaming */ +static int imx135_start_streaming(struct imx135 *imx135) +{ + int ret; + + /* Set init register settings */ + ret = imx135_set_register_array(imx135, imx135_global_init_settings, + ARRAY_SIZE( + imx135_global_init_settings)); + if (ret < 0) { + dev_err(imx135->dev, "Could not set init registers\n"); + return ret; + } + + /* Set current frame format */ + ret = imx135_write_current_format(imx135, &imx135->current_format); + if (ret < 0) { + dev_err(imx135->dev, "Could not set frame format\n"); + return ret; + } + + /* Apply default values of current mode */ + ret = imx135_set_register_array(imx135, imx135->current_mode->data, + imx135->current_mode->data_size); + if (ret < 0) { + dev_err(imx135->dev, "Could not set current mode\n"); + return ret; + } + + /* Apply customized values from user */ + ret = v4l2_ctrl_handler_setup(imx135->sd.ctrl_handler); + if (ret) { + dev_err(imx135->dev, "Could not sync v4l2 controls\n"); + return ret; + } + + ret = imx135_write_reg(imx135, IMX135_STANDBY, 0x00); + if (ret < 0) + return ret; + + msleep(30); + + /* Start streaming */ + return imx135_write_reg(imx135, IMX135_XMSTA, 0x00); +} + +static int imx135_set_stream(struct v4l2_subdev *sd, int enable) +{ + struct imx135 *imx135 = to_imx135(sd); + int ret = 0; + + if (enable) { + ret = pm_runtime_get_sync(imx135->dev); + if (ret < 0) { + pm_runtime_put_noidle(imx135->dev); + goto unlock_and_return; + } + + ret = imx135_start_streaming(imx135); + if (ret) { + dev_err(imx135->dev, "Start stream failed\n"); + pm_runtime_put(imx135->dev); + goto unlock_and_return; + } + } else { + imx135_stop_streaming(imx135); + pm_runtime_put(imx135->dev); + } + +unlock_and_return: + + return ret; +} + +static int imx135_get_regulators(struct device *dev, struct imx135 *imx135) +{ + unsigned int i; + + for (i = 0; i < IMX135_NUM_SUPPLIES; i++) + imx135->supplies[i].supply = imx135_supply_name[i]; + + return devm_regulator_bulk_get(dev, IMX135_NUM_SUPPLIES, + imx135->supplies); +} + +static int match_depend(struct device *dev, const void *data) +{ + return (dev && dev->fwnode == data) ? 1 : 0; +} + +static int imx135_power_on(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct imx135 *imx135 = to_imx135(sd); + struct acpi_handle *dev_handle = ACPI_HANDLE(&client->dev); + struct acpi_handle_list dep_devices; + acpi_status status; + int ret; + int i; + + if (acpi_has_method(dev_handle, "_DEP")) { + status = acpi_evaluate_reference(dev_handle, "_DEP", NULL, + &dep_devices); + if (ACPI_FAILURE(status)) { + printk("Failed to evaluate _DEP.\n"); + return -ENODEV; + } + + for (i = 0; i < dep_devices.count; i++) { + struct acpi_device *device; + struct acpi_device_info *info; + + status = acpi_get_object_info(dep_devices.handles[i], &info); + if (ACPI_FAILURE(status)) { + printk("Error reading _DEP device info\n"); + return -ENODEV; + } + + if (info->valid & ACPI_VALID_HID && + !strcmp(info->hardware_id.string, "INT3472")) { + if (acpi_bus_get_device(dep_devices.handles[i], &device)) + return -ENODEV; + + dev = bus_find_device(&platform_bus_type, NULL, + &device->fwnode, match_depend); + if (dev) { + dev_info(&client->dev, "Dependent platform device found %s\n", + dev_name(dev)); + break; + } + } + } + } + + ret = regulator_bulk_enable(IMX135_NUM_SUPPLIES, imx135->supplies); + if (ret) { + dev_err(imx135->dev, "Failed to enable regulators\n"); + return ret; + } + + usleep_range(1, 2); + gpiod_set_value_cansleep(imx135->rst_gpio, 1); + usleep_range(30000, 31000); + + return 0; +} + +static int imx135_power_off(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct imx135 *imx135 = to_imx135(sd); + + gpiod_set_value_cansleep(imx135->rst_gpio, 0); + regulator_bulk_disable(IMX135_NUM_SUPPLIES, imx135->supplies); + + return 0; +} + +static const struct dev_pm_ops imx135_pm_ops = { + SET_RUNTIME_PM_OPS(imx135_power_on, imx135_power_off, NULL) +}; + +static const struct v4l2_subdev_video_ops imx135_video_ops = { + .s_stream = imx135_set_stream, +}; + +static const struct v4l2_subdev_pad_ops imx135_pad_ops = { + .init_cfg = imx135_entity_init_cfg, + .enum_mbus_code = imx135_enum_mbus_code, + .get_fmt = imx135_get_fmt, + .set_fmt = imx135_set_fmt, +}; + +static const struct v4l2_subdev_ops imx135_subdev_ops = { + .video = &imx135_video_ops, + .pad = &imx135_pad_ops, +}; + +static const struct media_entity_operations imx135_subdev_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +static int imx135_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct imx135 *imx135; + int ret; + + printk("imx135: probing new device"); + + imx135 = devm_kzalloc(dev, sizeof(*imx135), GFP_KERNEL); + if (!imx135) + return -ENOMEM; + + imx135->dev = dev; + imx135->regmap = devm_regmap_init_i2c(client, &imx135_regmap_config); + if (IS_ERR(imx135->regmap)) { + dev_err(dev, "Unable to initialize I2C\n"); + return -ENODEV; + } + + /* set default mode to max resolution */ + imx135->current_mode = &imx135_modes[0]; + + ret = imx135_get_regulators(dev, imx135); + if (ret < 0) { + dev_err(dev, "Cannot get regulators\n"); + return ret; + } + + imx135->rst_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_ASIS); + if (IS_ERR(imx135->rst_gpio)) { + dev_err(dev, "Cannot get reset gpio\n"); + ret = PTR_ERR(imx135->rst_gpio); + return ret; + } + + mutex_init(&imx135->lock); + + v4l2_ctrl_handler_init(&imx135->ctrls, 3); + + v4l2_ctrl_new_std(&imx135->ctrls, &imx135_ctrl_ops, + V4L2_CID_GAIN, 0, 72, 1, 0); + imx135->link_freq = + v4l2_ctrl_new_int_menu(&imx135->ctrls, + &imx135_ctrl_ops, + V4L2_CID_LINK_FREQ, + ARRAY_SIZE(imx135_link_freq) - 1, + 0, imx135_link_freq); + if (imx135->link_freq) + imx135->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + imx135->pixel_rate = v4l2_ctrl_new_std(&imx135->ctrls, &imx135_ctrl_ops, + V4L2_CID_PIXEL_RATE, 1, + INT_MAX, 1, + imx135_modes[0].pixel_rate); + + imx135->sd.ctrl_handler = &imx135->ctrls; + + if (imx135->ctrls.error) { + dev_err(dev, "Control initialization error %d\n", + imx135->ctrls.error); + ret = imx135->ctrls.error; + goto free_ctrl; + } + + v4l2_i2c_subdev_init(&imx135->sd, client, &imx135_subdev_ops); + imx135->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + imx135->sd.dev = &client->dev; + imx135->sd.entity.ops = &imx135_subdev_entity_ops; + imx135->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + + imx135->pad.flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&imx135->sd.entity, 1, &imx135->pad); + if (ret < 0) { + dev_err(dev, "Could not register media entity\n"); + goto free_ctrl; + } + + ret = v4l2_async_register_subdev(&imx135->sd); + if (ret < 0) { + dev_err(dev, "Could not register v4l2 device\n"); + goto free_entity; + } + + /* Power on the device to match runtime PM state below */ + ret = imx135_power_on(dev); + if (ret < 0) { + dev_err(dev, "Could not power on the device\n"); + goto free_entity; + } + + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + pm_runtime_idle(dev); + + return 0; + +free_entity: + media_entity_cleanup(&imx135->sd.entity); +free_ctrl: + v4l2_ctrl_handler_free(&imx135->ctrls); + mutex_destroy(&imx135->lock); + + return ret; +} + +static int imx135_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct imx135 *imx135 = to_imx135(sd); + + v4l2_async_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(sd->ctrl_handler); + + mutex_destroy(&imx135->lock); + + pm_runtime_disable(imx135->dev); + if (!pm_runtime_status_suspended(imx135->dev)) + imx135_power_off(imx135->dev); + pm_runtime_set_suspended(imx135->dev); + + return 0; +} + +#ifdef CONFIG_ACPI +static const struct acpi_device_id imx135_acpi_ids[] = { + {"INT3471"}, + {} +}; + +MODULE_DEVICE_TABLE(acpi, imx135_acpi_ids); +#endif + +static struct i2c_driver imx135_i2c_driver = { + .driver = { + .name = "imx135", + .pm = &imx135_pm_ops, + .acpi_match_table = ACPI_PTR(imx135_acpi_ids), + }, + .probe = imx135_probe, + .remove = imx135_remove, +}; + +module_i2c_driver(imx135_i2c_driver); + +MODULE_DESCRIPTION("Sony IMX135 CMOS Image Sensor Driver"); +MODULE_AUTHOR("Jake Day <jake@ninebysix.com>"); +MODULE_LICENSE("GPL v2"); |
