From 8bf5313158312b395ee80594531b9cdfdb2833a5 Mon Sep 17 00:00:00 2001 From: Vladimir Barinov Date: Fri, 2 Feb 2018 15:50:29 +0300 Subject: LVDS: unify TI9X4 deserilalizers family, add V3MZF board 1) unify TI9X4 deseializers (TI954, TI964) 2) add V3MZF board 3) shorten deserilziers name in Kconfig/Makefile 4) add camera sensor AR0220 --- .../linux-renesas/0030-Gen3-LVDS-cameras.patch | 8876 ++++++++++---------- .../0040-arm64-dts-renesas-add-ADAS-boards.patch | 1919 ++--- .../recipes-kernel/linux/linux-renesas/condor.cfg | 2 +- .../recipes-kernel/linux/linux-renesas/eagle.cfg | 2 +- .../linux/linux-renesas/salvator-x.cfg | 2 +- .../recipes-kernel/linux/linux-renesas/ulcb.cfg | 5 +- .../recipes-kernel/linux/linux-renesas/v3msk.cfg | 5 +- 7 files changed, 5421 insertions(+), 5390 deletions(-) (limited to 'meta-rcar-gen3-adas/recipes-kernel') diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0030-Gen3-LVDS-cameras.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0030-Gen3-LVDS-cameras.patch index 67728ff..3c80601 100644 --- a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0030-Gen3-LVDS-cameras.patch +++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0030-Gen3-LVDS-cameras.patch @@ -4,41 +4,45 @@ Date: Sun, 14 May 2017 15:20:01 +0300 Subject: [PATCH] Gen3: LVDS cameras This add Gen3 LVDS cameras support: -- deserializers: MAX9286, TI964, TI954, TI960 -- cameras: ov10635, ov490+ov10640, ov495+OV2775, ar0132, ap0101+ar014x +- deserializers: MAX9286, DS90UB954/960/964 +- cameras: ov10635, ov490+ov10640, ov495+OV2775, ar0132, ar0220, + ap0101+ar014x Signed-off-by: Vladimir Barinov --- - drivers/media/i2c/soc_camera/Kconfig | 47 + - drivers/media/i2c/soc_camera/Makefile | 7 + + drivers/media/i2c/soc_camera/Kconfig | 41 + + drivers/media/i2c/soc_camera/Makefile | 6 + drivers/media/i2c/soc_camera/ap0101_ar014x.c | 588 +++++++++++ drivers/media/i2c/soc_camera/ap0101_ar014x.h | 28 + - drivers/media/i2c/soc_camera/ar0132.c | 582 +++++++++++ + drivers/media/i2c/soc_camera/ar0132.c | 565 +++++++++++ drivers/media/i2c/soc_camera/ar0132.h | 213 ++++ + drivers/media/i2c/soc_camera/ar0220.c | 528 ++++++++++ + drivers/media/i2c/soc_camera/ar0220.h | 309 ++++++ drivers/media/i2c/soc_camera/max9286.c | 697 +++++++++++++ drivers/media/i2c/soc_camera/max9286.h | 244 +++++ drivers/media/i2c/soc_camera/ov10635.c | 759 ++++++++++++++ - drivers/media/i2c/soc_camera/ov10635.h | 1139 +++++++++++++++++++++ + drivers/media/i2c/soc_camera/ov10635.h | 1139 ++++++++++++++++++++++ drivers/media/i2c/soc_camera/ov10635_debug.h | 54 + - drivers/media/i2c/soc_camera/ov106xx.c | 117 +++ - drivers/media/i2c/soc_camera/ov490_ov10640.c | 1160 ++++++++++++++++++++++ + drivers/media/i2c/soc_camera/ov106xx.c | 128 +++ + drivers/media/i2c/soc_camera/ov490_ov10640.c | 1133 +++++++++++++++++++++ drivers/media/i2c/soc_camera/ov490_ov10640.h | 102 ++ - drivers/media/i2c/soc_camera/ov495_ov2775.c | 658 ++++++++++++ + drivers/media/i2c/soc_camera/ov495_ov2775.c | 639 ++++++++++++ drivers/media/i2c/soc_camera/ov495_ov2775.h | 23 + - drivers/media/i2c/soc_camera/ti954_ti9x3.c | 439 ++++++++ - drivers/media/i2c/soc_camera/ti964_ti9x3.c | 408 ++++++++ - drivers/media/i2c/soc_camera/ti9x4_ti9x3.h | 153 +++ + drivers/media/i2c/soc_camera/ti9x4.c | 520 ++++++++++ + drivers/media/i2c/soc_camera/ti9x4.h | 156 +++ drivers/media/platform/soc_camera/rcar_csi2.c | 297 ++++-- - drivers/media/platform/soc_camera/rcar_vin.c | 211 +++- + drivers/media/platform/soc_camera/rcar_vin.c | 194 +++- drivers/media/platform/soc_camera/soc_camera.c | 17 +- drivers/media/platform/soc_camera/soc_mediabus.c | 16 + include/media/drv-intf/soc_mediabus.h | 3 + include/media/soc_camera.h | 1 + - 25 files changed, 7854 insertions(+), 109 deletions(-) + 26 files changed, 8291 insertions(+), 109 deletions(-) create mode 100644 drivers/media/i2c/soc_camera/ap0101_ar014x.c create mode 100644 drivers/media/i2c/soc_camera/ap0101_ar014x.h create mode 100644 drivers/media/i2c/soc_camera/ar0132.c create mode 100644 drivers/media/i2c/soc_camera/ar0132.h + create mode 100644 drivers/media/i2c/soc_camera/ar0220.c + create mode 100644 drivers/media/i2c/soc_camera/ar0220.h create mode 100644 drivers/media/i2c/soc_camera/max9286.c create mode 100644 drivers/media/i2c/soc_camera/max9286.h create mode 100644 drivers/media/i2c/soc_camera/ov10635.c @@ -49,42 +53,47 @@ Signed-off-by: Vladimir Barinov create mode 100644 drivers/media/i2c/soc_camera/ov490_ov10640.h create mode 100644 drivers/media/i2c/soc_camera/ov495_ov2775.c create mode 100644 drivers/media/i2c/soc_camera/ov495_ov2775.h - create mode 100644 drivers/media/i2c/soc_camera/ti954_ti9x3.c - create mode 100644 drivers/media/i2c/soc_camera/ti964_ti9x3.c - create mode 100644 drivers/media/i2c/soc_camera/ti9x4_ti9x3.h + create mode 100644 drivers/media/i2c/soc_camera/ti9x4.c + create mode 100644 drivers/media/i2c/soc_camera/ti9x4.h diff --git a/drivers/media/i2c/soc_camera/Kconfig b/drivers/media/i2c/soc_camera/Kconfig -index 7704bcf..82da59f 100644 +index 7704bcf..d6377e9 100644 --- a/drivers/media/i2c/soc_camera/Kconfig +++ b/drivers/media/i2c/soc_camera/Kconfig -@@ -6,6 +6,53 @@ config SOC_CAMERA_IMX074 +@@ -6,6 +6,47 @@ config SOC_CAMERA_IMX074 help This driver supports IMX074 cameras from Sony -+config SOC_CAMERA_MAX9286_MAX9271 -+ tristate "max9286-max9271 GMSL support" ++config SOC_CAMERA_MAX9286 ++ tristate "max9286 GMSL support" + depends on SOC_CAMERA && I2C + help -+ This is a MAXIM max9286-max9271 GMSL driver ++ This is a MAXIM max9286 GMSL driver + +config SOC_CAMERA_OV106XX + tristate "ov106xx camera support" -+ depends on SOC_CAMERA && SOC_CAMERA_MAX9286_MAX9271 && I2C ++ depends on SOC_CAMERA && I2C + help + This is a runtime detected OmniVision ov10635 or ov490-ov10640 + or ov495-ov2775 sensors camera driver + ++config SOC_CAMERA_TI9X4 ++ tristate "ti9x4 FPDLinkIII support" ++ depends on SOC_CAMERA && I2C ++ help ++ This is an Texas Instruments ti9X4 FPDLinkIII driver ++ +if !SOC_CAMERA_OV106XX + +config SOC_CAMERA_OV10635 + tristate "ov10635 camera support" -+ depends on SOC_CAMERA && SOC_CAMERA_MAX9286_MAX9271 && I2C ++ depends on SOC_CAMERA && I2C + help + This is an OmniVision ov10635 sensor camera driver + +config SOC_CAMERA_OV490_OV10640 + tristate "ov490-ov10640 camera support" -+ depends on SOC_CAMERA && SOC_CAMERA_MAX9286_MAX9271 && I2C ++ depends on SOC_CAMERA && I2C + help + This is an OmniVision ov490-ov10640 sensor camera driver + @@ -95,31 +104,18 @@ index 7704bcf..82da59f 100644 + This is an OmniVision ov495-ov2775 sensor camera driver + +endif -+ -+config SOC_CAMERA_TI964_TI9X3 -+ tristate "ti964-ti9x3 FPDLinkIII support" -+ depends on SOC_CAMERA && I2C -+ help -+ This is an Texas Instruments ti964-ti9X3 FPDLinkIII driver -+ -+config SOC_CAMERA_TI954_TI9X3 -+ tristate "ti954-ti9X3 FPDLinkIII support" -+ depends on SOC_CAMERA && I2C -+ help -+ This is an Texas Instruments ti954-ti9X3 FPDLinkIII driver + 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 6f994f9..e88f6a9 100644 +index 6f994f9..58086d4 100644 --- a/drivers/media/i2c/soc_camera/Makefile +++ b/drivers/media/i2c/soc_camera/Makefile -@@ -1,8 +1,15 @@ +@@ -1,8 +1,14 @@ obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.o -+obj-$(CONFIG_SOC_CAMERA_MAX9286_MAX9271) += max9286.o -+obj-$(CONFIG_SOC_CAMERA_TI964_TI9X3) += ti964_ti9x3.o -+obj-$(CONFIG_SOC_CAMERA_TI954_TI9X3) += ti954_ti9x3.o ++obj-$(CONFIG_SOC_CAMERA_MAX9286) += max9286.o ++obj-$(CONFIG_SOC_CAMERA_TI9X4) += ti9x4.o obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o obj-$(CONFIG_SOC_CAMERA_MT9T112) += mt9t112.o @@ -761,10 +757,10 @@ index 0000000..16599a1 +}; diff --git a/drivers/media/i2c/soc_camera/ar0132.c b/drivers/media/i2c/soc_camera/ar0132.c new file mode 100644 -index 0000000..97d9878 +index 0000000..e124e6a --- /dev/null +++ b/drivers/media/i2c/soc_camera/ar0132.c -@@ -0,0 +1,582 @@ +@@ -0,0 +1,565 @@ +/* + * ON Semiconductor AR0132 sensor camera driver + * @@ -811,8 +807,7 @@ index 0000000..97d9878 + /* serializers */ + int max9286_addr; + int max9271_addr; -+ int ti964_addr; -+ int ti954_addr; ++ int ti9x4_addr; + int ti9x3_addr; + int port; + int gpio_resetb; @@ -1160,19 +1155,13 @@ index 0000000..97d9878 + break; + + if (!of_property_read_u32(rendpoint, "ti9x3-addr", &priv->ti9x3_addr) && -+ !of_property_match_string(rendpoint->parent->parent, "compatible", "ti,ti964-ti9x3") && -+ !of_property_read_u32(rendpoint->parent->parent, "reg", &priv->ti964_addr) && -+ !kstrtouint(strrchr(rendpoint->full_name, '@') + 1, 0, &priv->port)) -+ break; -+ -+ if (!of_property_read_u32(rendpoint, "ti9x3-addr", &priv->ti9x3_addr) && -+ !of_property_match_string(rendpoint->parent->parent, "compatible", "ti,ti954-ti9x3") && -+ !of_property_read_u32(rendpoint->parent->parent, "reg", &priv->ti954_addr) && ++ !of_property_match_string(rendpoint->parent->parent, "compatible", "ti,ti9x4") && ++ !of_property_read_u32(rendpoint->parent->parent, "reg", &priv->ti9x4_addr) && + !kstrtouint(strrchr(rendpoint->full_name, '@') + 1, 0, &priv->port)) + break; + } + -+ if (!priv->max9286_addr && !priv->ti964_addr && !priv->ti954_addr) { ++ if (!priv->max9286_addr && !priv->ti9x4_addr) { + dev_err(&client->dev, "deserializer does not present for AR0132\n"); + return -EINVAL; + } @@ -1188,18 +1177,8 @@ index 0000000..97d9878 + reg8_write(client, 0x0A, AR0132_I2C_ADDR << 1); /* Sensor native I2C address */ + usleep_range(2000, 2500); /* wait 2ms */ + }; -+ if (priv->ti964_addr) { -+ client->addr = priv->ti964_addr; /* Deserializer I2C address */ -+ -+ reg8_write(client, 0x4c, (priv->port << 4) | (1 << priv->port)); /* Select RX port number */ -+ usleep_range(2000, 2500); /* wait 2ms */ -+ reg8_write(client, 0x65, tmp_addr << 1); /* Sensor translated I2C address */ -+ reg8_write(client, 0x5d, AR0132_I2C_ADDR << 1); /* Sensor native I2C address */ -+ -+ reg8_write(client, 0x6e, 0xa9); /* GPIO0 - reset, GPIO1 - fsin */ -+ } -+ if (priv->ti954_addr) { -+ client->addr = priv->ti954_addr; /* Deserializer I2C address */ ++ if (priv->ti9x4_addr) { ++ client->addr = priv->ti9x4_addr; /* Deserializer I2C address */ + + reg8_write(client, 0x4c, (priv->port << 4) | (1 << priv->port)); /* Select RX port number */ + usleep_range(2000, 2500); /* wait 2ms */ @@ -1349,12 +1328,12 @@ index 0000000..97d9878 +#endif diff --git a/drivers/media/i2c/soc_camera/ar0132.h b/drivers/media/i2c/soc_camera/ar0132.h new file mode 100644 -index 0000000..bcee0e5 +index 0000000..bafa193 --- /dev/null +++ b/drivers/media/i2c/soc_camera/ar0132.h @@ -0,0 +1,213 @@ +/* -+ * ON Semiconductor ar0132 sensor camera wizard 1110x620@30/BGGR/BT601/12bit ++ * ON Semiconductor AR0132 sensor camera wizard 1110x620@30/BGGR/BT601/12bit + * + * Copyright (C) 2017 Cogent Embedded, Inc. + * @@ -1566,16 +1545,16 @@ index 0000000..bcee0e5 +{0x31D0, 0x0001}, +{0x30B0, 0x2002}, +}; -diff --git a/drivers/media/i2c/soc_camera/max9286.c b/drivers/media/i2c/soc_camera/max9286.c +diff --git a/drivers/media/i2c/soc_camera/ar0220.c b/drivers/media/i2c/soc_camera/ar0220.c new file mode 100644 -index 0000000..989c782 +index 0000000..ef2eb51 --- /dev/null -+++ b/drivers/media/i2c/soc_camera/max9286.c -@@ -0,0 +1,697 @@ ++++ b/drivers/media/i2c/soc_camera/ar0220.c +@@ -0,0 +1,528 @@ +/* -+ * MAXIM max9286 GMSL driver ++ * ON Semiconductor AR0220 sensor camera driver + * -+ * Copyright (C) 2015-2018 Cogent Embedded, Inc. ++ * Copyright (C) 2017-2018 Cogent Embedded, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the @@ -1584,573 +1563,347 @@ index 0000000..989c782 + */ + +#include ++#include +#include +#include -+#include -+#include -+#include +#include + ++#include +#include -+#include ++#include +#include -+#include + -+#include "max9286.h" -+ -+#define MAXIM_I2C_I2C_SPEED_837KHZ (0x7 << 2) /* 837kbps */ -+#define MAXIM_I2C_I2C_SPEED_533KHZ (0x6 << 2) /* 533kbps */ -+#define MAXIM_I2C_I2C_SPEED_339KHZ (0x5 << 2) /* 339 kbps */ -+#define MAXIM_I2C_I2C_SPEED_173KHZ (0x4 << 2) /* 174kbps */ -+#define MAXIM_I2C_I2C_SPEED_105KHZ (0x3 << 2) /* 105 kbps */ -+#define MAXIM_I2C_I2C_SPEED_085KHZ (0x2 << 2) /* 84.7 kbps */ -+#define MAXIM_I2C_I2C_SPEED_028KHZ (0x1 << 2) /* 28.3 kbps */ -+#define MAXIM_I2C_I2C_SPEED MAXIM_I2C_I2C_SPEED_339KHZ -+ -+struct max9286_priv { -+ struct v4l2_subdev sd[4]; -+ struct device_node *sd_of_node[4]; -+ int des_addr; -+ int des_quirk_addr; /* second MAX9286 on the same I2C bus */ -+ int links; -+ int links_mask; -+ int lanes; -+ int csi_rate; -+ const char *fsync_mode; -+ int fsync_period; -+ char pclk_rising_edge; -+ int gpio_resetb; -+ int active_low_resetb; -+ int him; -+ int hsync; -+ int vsync; -+ int timeout; -+ int poc_delay; -+ atomic_t use_count; -+ u32 csi2_outord; -+ struct i2c_client *client; -+ int max9271_addr_map[4]; -+ int ser_id; -+ struct regulator *poc_supply[4]; /* PoC power supply */ -+}; ++#include "ar0220.h" + -+static char fsync_mode_default[20] = "manual"; /* manual, automatic, semi-automatic, external */ ++#define AR0220_I2C_ADDR 0x10 ++//#define AR0220_I2C_ADDR 0x54 // eeprom + -+static int conf_link; -+module_param(conf_link, int, 0644); -+MODULE_PARM_DESC(conf_link, " Force configuration link. Used only if robust firmware flashing required (f.e. recovery)"); ++#define AR0220_PID 0x3000 ++#define AR0220_VERSION_REG 0x0C54 + -+static int poc_trig; -+module_param(poc_trig, int, 0644); -+MODULE_PARM_DESC(poc_trig, " Use PoC triggering during reverse channel setup. Useful on systems with dedicated PoC and unstable ser-des lock */"); ++#define AR0220_MEDIA_BUS_FMT MEDIA_BUS_FMT_SBGGR8_1X8 + -+static int him; -+module_param(him, int, 0644); -+MODULE_PARM_DESC(him, " Use High-Immunity mode (default: leagacy mode) */"); ++struct ar0220_priv { ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct media_pad pad; ++ struct v4l2_rect rect; ++ int init_complete; ++ u8 id[6]; ++ int exposure; ++ int gain; ++ int autogain; ++ /* serializers */ ++ int ti9x4_addr; ++ int ti9x3_addr; ++ int port; ++ int gpio_resetb; ++ int gpio_fsin; + -+static int fsync_period; -+module_param(fsync_period, int, 0644); -+MODULE_PARM_DESC(fsync_period, " Frame sync period (default: 3.2MHz) */"); ++}; + -+static int hsync; -+module_param(hsync, int, 0644); -+MODULE_PARM_DESC(hsync, " HSYNC invertion (default: 0 - not inverted) */"); ++static inline struct ar0220_priv *to_ar0220(const struct i2c_client *client) ++{ ++ return container_of(i2c_get_clientdata(client), struct ar0220_priv, sd); ++} + -+static int vsync = 1; -+module_param(vsync, int, 0644); -+MODULE_PARM_DESC(vsync, " VSYNC invertion (default: 1 - inverted) */"); ++static int ar0220_set_regs(struct i2c_client *client, ++ const struct ar0220_reg *regs, int nr_regs) ++{ ++ int i; + -+static int gpio_resetb; -+module_param(gpio_resetb, int, 0644); -+MODULE_PARM_DESC(gpio_resetb, " Serializer GPIO reset (default: 0 - not used) */"); ++ for (i = 0; i < nr_regs; i++) { ++ if (regs[i].reg == AR0220_DELAY) { ++ mdelay(regs[i].val); ++ continue; ++ } + -+static int active_low_resetb; -+module_param(active_low_resetb, int, 0644); -+MODULE_PARM_DESC(active_low_resetb, " Serializer GPIO reset level (default: 0 - active high) */"); ++ reg16_write16(client, regs[i].reg, regs[i].val); ++ } + -+static int poc_delay; -+module_param(poc_delay, int, 0644); -+MODULE_PARM_DESC(poc_delay, " Delay in ms after POC enable (default: 0 ms) */"); ++ return 0; ++} + -+static char* ser_name(int id) ++static int ar0220_s_stream(struct v4l2_subdev *sd, int enable) +{ -+ switch (id) { -+ case MAX9271_ID: -+ return "MAX9271"; -+ case MAX96705_ID: -+ return "MAX96705"; -+ default: -+ return "unknown"; -+ } ++ return 0; +} + -+static void max9286_preinit(struct i2c_client *client, int addr) ++static int ar0220_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) +{ -+ struct max9286_priv *priv = i2c_get_clientdata(client); ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ar0220_priv *priv = to_ar0220(client); + -+ client->addr = addr; /* MAX9286-CAMx I2C */ -+ reg8_write(client, 0x0a, 0x00); /* disable reverse control for all cams */ -+ reg8_write(client, 0x00, 0x00); /* disable all GMSL links [0:3] */ -+ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ -+ reg8_write(client, 0x1c, priv->him ? 0xf4 : 0x04); /* high-immunity or legacy mode */ ++ if (format->pad) ++ return -EINVAL; ++ ++ mf->width = priv->rect.width; ++ mf->height = priv->rect.height; ++ mf->code = AR0220_MEDIA_BUS_FMT; ++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M; ++ mf->field = V4L2_FIELD_NONE; ++ ++ return 0; +} + -+static void max9286_sensor_reset(struct i2c_client *client, int addr, int reset_on) ++static int ar0220_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) +{ -+ struct max9286_priv *priv = i2c_get_clientdata(client); ++ struct v4l2_mbus_framefmt *mf = &format->format; + -+ if (priv->gpio_resetb < 1 || priv->gpio_resetb > 5) -+ return; ++ mf->code = AR0220_MEDIA_BUS_FMT; ++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M; ++ mf->field = V4L2_FIELD_NONE; + -+ /* sensor reset/unreset */ -+ client->addr = addr; /* MAX9271-CAMx I2C */ -+ reg8_write(client, 0x0f, (0xfe & ~BIT(priv->gpio_resetb)) | /* set GPIOn value to reset/unreset */ -+ ((priv->active_low_resetb ? BIT(priv->gpio_resetb) : 0) ^ reset_on)); -+ reg8_write(client, 0x0e, 0x42 | BIT(priv->gpio_resetb)); /* set GPIOn direction output */ ++ if (format->which == V4L2_SUBDEV_FORMAT_TRY) ++ cfg->try_fmt = *mf; ++ ++ return 0; +} + -+static void max9286_postinit(struct i2c_client *client, int addr) ++static int ar0220_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) +{ -+ struct max9286_priv *priv = i2c_get_clientdata(client); -+ int idx; ++ if (code->pad || code->index > 0) ++ return -EINVAL; + -+ for (idx = 0; idx < priv->links; idx++) { -+ client->addr = priv->des_addr; /* MAX9286 I2C */ -+ reg8_write(client, 0x0a, 0x11 << idx); /* enable reverse/forward control for CAMx */ ++ code->code = AR0220_MEDIA_BUS_FMT; + -+ client->addr = priv->max9271_addr_map[idx]; /* MAX9271-CAMx I2C */ -+ max9286_sensor_reset(client, client->addr, 0); /* sensor unreset */ -+ } ++ return 0; ++} + -+ client->addr = addr; /* MAX9286 I2C */ -+ reg8_write(client, 0x0a, 0x00); /* disable reverse control for all cams */ -+ reg8_write(client, 0x00, 0xe0 | priv->links_mask); /* enable GMSL link for CAMs */ -+ reg8_write(client, 0x0b, priv->csi2_outord); /* CSI2 output order */ -+ reg8_write(client, 0x15, 0x9b); /* enable CSI output, VC is set accordingly to Link number, BIT7 magic must be set */ -+ reg8_write(client, 0x1b, priv->links_mask); /* enable equalizer for CAMs */ -+ usleep_range(5000, 5500); /* wait 2ms after any change of reverse channel settings */ ++static int ar0220_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ar0220_priv *priv = to_ar0220(client); + -+ if (strcmp(priv->fsync_mode, "manual") == 0) { -+ reg8_write(client, 0x01, 0x00); /* manual: FRAMESYNC set manually via [0x06:0x08] regs */ -+ } else if (strcmp(priv->fsync_mode, "automatic") == 0) { -+ reg8_write(client, 0x01, 0x02); /* automatic: FRAMESYNC taken from the slowest Link */ -+ } else if (strcmp(priv->fsync_mode, "semi-automatic") == 0) { -+ reg8_write(client, 0x01, 0x01); /* semi-automatic: FRAMESYNC taken from the slowest Link */ -+ } else if (strcmp(priv->fsync_mode, "external") == 0) { -+ reg8_write(client, 0x01, 0xc0); /* ECU (aka MCU) based FrameSync using GPI-to-GPO */ -+ } ++ memcpy(edid->edid, priv->id, 6); ++ ++ edid->edid[6] = 0xff; ++ edid->edid[7] = client->addr; ++ edid->edid[8] = AR0220_VERSION_REG >> 8; ++ edid->edid[9] = AR0220_VERSION_REG & 0xff; ++ ++ return 0; +} + -+static int max9286_reverse_channel_setup(struct i2c_client *client, int idx) ++static int ar0220_set_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_selection *sel) +{ -+ struct max9286_priv *priv = i2c_get_clientdata(client); -+ u8 val = 0; -+ int timeout = priv->timeout; -+ char timeout_str[10]; -+ int ret = 0; ++ struct v4l2_rect *rect = &sel->r; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ar0220_priv *priv = to_ar0220(client); + -+ /* Reverse channel enable */ -+ client->addr = priv->des_addr; /* MAX9286-CAMx I2C */ -+ reg8_write(client, 0x3f, 0x4f); /* enable custom reverse channel & first pulse length */ -+ reg8_write(client, 0x34, 0xa2 | MAXIM_I2C_I2C_SPEED); /* enable artificial ACKs, I2C speed set */ -+ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ -+ reg8_write(client, 0x00, 0xe0 | BIT(idx)); /* enable GMSL link for CAMx */ -+ reg8_write(client, 0x0a, 0x11 << idx); /* enable reverse control for CAMx */ -+ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ ++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || ++ sel->target != V4L2_SEL_TGT_CROP) ++ return -EINVAL; + -+ for (;;) { -+ client->addr = priv->des_addr; /* MAX9286-CAMx I2C */ -+ reg8_write(client, 0x3b, 0x1e); /* first pulse length rise time changed from 300ns to 200ns, amplitude 100mV */ -+ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ ++ rect->left = ALIGN(rect->left, 2); ++ rect->top = ALIGN(rect->top, 2); ++ rect->width = ALIGN(rect->width, 2); ++ rect->height = ALIGN(rect->height, 2); + -+ client->addr = 0x40; /* MAX9271-CAMx I2C */ -+ reg8_write(client, 0x04, 0x43); /* wake-up, enable reverse_control/conf_link */ -+ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ -+ reg8_write(client, 0x08, 0x01); /* reverse channel receiver high threshold enable */ -+ reg8_write(client, 0x97, priv->him ? 0xaf : 0x5f); /* enable reverse control channel programming (MAX96705-MAX96711 only) */ -+ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ ++ if ((rect->left + rect->width > AR0220_MAX_WIDTH) || ++ (rect->top + rect->height > AR0220_MAX_HEIGHT)) ++ *rect = priv->rect; + -+ client->addr = priv->des_addr; /* MAX9286-CAMx I2C */ -+ reg8_write(client, 0x3b, 0x19); /* reverse channel increase amplitude 170mV to compensate high threshold enabled */ -+ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ -+ -+ client->addr = 0x40; /* MAX9271-CAMx I2C */ -+ reg8_read(client, 0x1e, &val); /* read max9271 ID */ -+ if (val == MAX9271_ID || val == MAX96705_ID || --timeout == 0) { -+ priv->ser_id = val; -+ break; -+ } -+ -+ /* Check if already initialized (after reboot/reset ?) */ -+ client->addr = priv->max9271_addr_map[idx]; /* MAX9271-CAMx I2C */ -+ reg8_read(client, 0x1e, &val); /* read max9271 ID */ -+ if (val == MAX9271_ID || val == MAX96705_ID) { -+ priv->ser_id = val; -+ reg8_write(client, 0x04, 0x43); /* enable reverse_control/conf_link */ -+ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ -+ ret = -EADDRINUSE; -+ break; -+ } -+ -+ if (timeout == priv->timeout / 2 && poc_trig) { -+ if (!IS_ERR(priv->poc_supply[idx])) { -+ if (regulator_disable(priv->poc_supply[idx])) -+ dev_err(&client->dev, "fail to disable POC%d regulator\n", idx); -+ mdelay(200); -+ if (regulator_enable(priv->poc_supply[idx])) -+ dev_err(&client->dev, "fail to enable POC%d regulator\n", idx); -+ mdelay(priv->poc_delay); -+ } -+ } -+ } -+ -+ max9286_sensor_reset(client, client->addr, 1); /* sensor reset */ -+ -+ if (!timeout) { -+ ret = -ETIMEDOUT; -+ goto out; -+ } -+ -+ priv->links_mask |= BIT(idx); -+ priv->csi2_outord &= ~(0x3 << (idx * 2)); -+ priv->csi2_outord |= ((hweight8(priv->links_mask) - 1) << (idx * 2)); -+ -+out: -+ sprintf(timeout_str, "retries=%d", priv->timeout - timeout); -+ dev_info(&client->dev, "link%d %s %sat 0x%x %s %s\n", idx, ser_name(priv->ser_id), -+ ret == -EADDRINUSE ? "already " : "", priv->max9271_addr_map[idx], -+ ret == -ETIMEDOUT ? "not found: timeout GMSL link establish" : "", -+ priv->timeout - timeout? timeout_str : ""); -+ -+ return ret; -+} -+ -+static void max9286_initial_setup(struct i2c_client *client) -+{ -+ struct max9286_priv *priv = i2c_get_clientdata(client); -+ -+ /* Initial setup */ -+ client->addr = priv->des_addr; /* MAX9286-CAMx I2C */ -+ reg8_write(client, 0x15, 0x13); /* disable CSI output, VC is set accordingly to Link number */ -+ reg8_write(client, 0x69, 0x0f); /* mask CSI forwarding from all links */ -+ switch (priv->lanes) { -+ case 1: -+ reg8_write(client, 0x12, 0x33); /* enable CSI-2 Lane D0, DBL mode, YUV422 8-bit*/ -+ break; -+ case 2: -+ reg8_write(client, 0x12, 0x73); /* enable CSI-2 Lanes D0,D1, DBL mode, YUV422 8-bit*/ -+ break; -+ case 3: -+ reg8_write(client, 0x12, 0xd3); /* enable CSI-2 Lanes D0-D2, DBL mode, YUV422 8-bit*/ -+ break; -+ case 4: -+ reg8_write(client, 0x12, 0xf3); /* enable CSI-2 Lanes D0-D3, DBL mode, YUV422 8-bit*/ -+ break; -+ default: -+ dev_err(&client->dev, "CSI2 lanes number is invalid (%d)\n", priv->lanes); -+ } -+ -+ /* Start GMSL initialization with FSYNC disabled. This is required for some odd LVDS cameras */ -+ reg8_write(client, 0x01, 0xc0); /* ECU (aka MCU) based FrameSync using GPI-to-GPO */ -+ reg8_write(client, 0x06, priv->fsync_period & 0xff); -+ reg8_write(client, 0x07, (priv->fsync_period >> 8) & 0xff); -+ reg8_write(client, 0x08, priv->fsync_period >> 16); ++ priv->rect.left = rect->left; ++ priv->rect.top = rect->top; ++ priv->rect.width = rect->width; ++ priv->rect.height = rect->height; + -+ reg8_write(client, 0x63, 0); /* disable overlap window */ -+ reg8_write(client, 0x64, 0); -+ reg8_write(client, 0x0c, 0x91 | (priv->vsync ? BIT(3) : 0) | (priv->hsync ? BIT(2) : 0)); /* enable HS/VS encoding, use D14/15 for HS/VS, invert HS/VS */ -+ reg8_write(client, 0x19, 0x0c); /* Drive HSTRAIL state for 120ns after the last payload bit */ ++ return 0; +} + -+static void max9286_gmsl_link_setup(struct i2c_client *client, int idx) ++static int ar0220_get_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_selection *sel) +{ -+ struct max9286_priv *priv = i2c_get_clientdata(client); -+ -+ /* GMSL setup */ -+ client->addr = 0x40; /* MAX9271-CAMx I2C */ -+ reg8_write(client, 0x0d, 0x22 | MAXIM_I2C_I2C_SPEED); /* disable artificial ACK, I2C speed set */ -+ reg8_write(client, 0x07, 0x84 | (priv->pclk_rising_edge ? 0 : 0x10)); /* RAW/YUV, PCLK edge, HS/VS encoding enabled */ -+ usleep_range(2000, 2500); /* wait 2ms */ -+ reg8_write(client, 0x02, 0xff); /* spread spectrum +-4%, pclk range automatic, Gbps automatic */ -+ usleep_range(2000, 2500); /* wait 2ms */ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ar0220_priv *priv = to_ar0220(client); + -+ if (priv->ser_id == MAX96705_ID) { -+ /* setup crossbar in DBL mode: reverse DVP bus */ -+ reg8_write(client, 0x20, 0x07); -+ reg8_write(client, 0x21, 0x06); -+ reg8_write(client, 0x22, 0x05); -+ reg8_write(client, 0x23, 0x04); -+ reg8_write(client, 0x24, 0x03); -+ reg8_write(client, 0x25, 0x02); -+ reg8_write(client, 0x26, 0x01); -+ reg8_write(client, 0x27, 0x00); ++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) ++ return -EINVAL; + -+ reg8_write(client, 0x30, 0x17); -+ reg8_write(client, 0x31, 0x16); -+ reg8_write(client, 0x32, 0x15); -+ reg8_write(client, 0x33, 0x14); -+ reg8_write(client, 0x34, 0x13); -+ reg8_write(client, 0x35, 0x12); -+ reg8_write(client, 0x36, 0x11); -+ reg8_write(client, 0x37, 0x10); ++ switch (sel->target) { ++ case V4L2_SEL_TGT_CROP_BOUNDS: ++ sel->r.left = 0; ++ sel->r.top = 0; ++ sel->r.width = AR0220_MAX_WIDTH; ++ sel->r.height = AR0220_MAX_HEIGHT; ++ return 0; ++ case V4L2_SEL_TGT_CROP_DEFAULT: ++ sel->r.left = 0; ++ sel->r.top = 0; ++ sel->r.width = AR0220_MAX_WIDTH; ++ sel->r.height = AR0220_MAX_HEIGHT; ++ return 0; ++ case V4L2_SEL_TGT_CROP: ++ sel->r = priv->rect; ++ return 0; ++ default: ++ return -EINVAL; + } -+ -+ client->addr = priv->des_addr; /* MAX9286-CAMx I2C */ -+ reg8_write(client, 0x34, 0x22 | MAXIM_I2C_I2C_SPEED); /* disable artificial ACK, I2C speed set */ -+ usleep_range(2000, 2500); /* wait 2ms */ -+ -+ /* I2C translator setup */ -+ client->addr = 0x40; /* MAX9271-CAMx I2C */ -+// reg8_write(client, 0x09, maxim_map[2][idx] << 1); /* SENSOR I2C translated - must be set by sensor driver */ -+// reg8_write(client, 0x0A, 0x30 << 1); /* SENSOR I2C native - must be set by sensor driver */ -+ reg8_write(client, 0x0B, BROADCAST << 1); /* broadcast I2C */ -+ reg8_write(client, 0x0C, priv->max9271_addr_map[idx] << 1); /* MAX9271-CAMx I2C new */ -+ /* I2C addresse change */ -+ reg8_write(client, 0x01, priv->des_addr << 1); /* MAX9286 I2C */ -+ reg8_write(client, 0x00, priv->max9271_addr_map[idx] << 1); /* MAX9271-CAM0 I2C new */ -+ usleep_range(2000, 2500); /* wait 2ms */ -+ /* put MAX9271 in configuration link state */ -+ client->addr = priv->max9271_addr_map[idx]; /* MAX9271-CAMx I2C new */ -+ reg8_write(client, 0x04, 0x43); /* enable reverse_control/conf_link */ -+ usleep_range(2000, 2500); /* wait 2ms */ -+#ifdef MAXIM_DUMP -+ client->addr = priv->des_addr; /* MAX9286-CAMx I2C */ -+ maxim_max927x_dump_regs(client); -+ client->addr = priv->max9271_addr_map[idx]; /* MAX9271-CAMx I2C new */ -+ maxim_max927x_dump_regs(client); -+#endif +} + -+static int max9286_initialize(struct i2c_client *client) ++static int ar0220_g_mbus_config(struct v4l2_subdev *sd, ++ struct v4l2_mbus_config *cfg) +{ -+ struct max9286_priv *priv = i2c_get_clientdata(client); -+ int idx, ret; -+ -+ dev_info(&client->dev, "LINKs=%d, LANES=%d, FSYNC mode=%s, FSYNC period=%d, PCLK edge=%s\n", -+ priv->links, priv->lanes, priv->fsync_mode, priv->fsync_period, -+ priv->pclk_rising_edge ? "rising" : "falling"); -+ -+ if (priv->des_quirk_addr) -+ max9286_preinit(client, priv->des_quirk_addr); -+ -+ max9286_preinit(client, priv->des_addr); -+ max9286_initial_setup(client); -+ -+ for (idx = 0; idx < priv->links; idx++) { -+ if (!IS_ERR(priv->poc_supply[idx])) { -+ if (regulator_enable(priv->poc_supply[idx])) -+ dev_err(&client->dev, "fail to enable POC%d regulator\n", idx); -+ mdelay(priv->poc_delay); -+ } -+ -+ ret = max9286_reverse_channel_setup(client, idx); -+ if (ret) -+ continue; -+ max9286_gmsl_link_setup(client, idx); -+ } -+ -+ max9286_postinit(client, priv->des_addr); -+ -+ client->addr = priv->des_addr; ++ cfg->flags = V4L2_MBUS_CSI2_1_LANE | V4L2_MBUS_CSI2_CHANNEL_0 | ++ V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; ++ cfg->type = V4L2_MBUS_CSI2; + + return 0; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG -+static int max9286_g_register(struct v4l2_subdev *sd, -+ struct v4l2_dbg_register *reg) ++static int ar0220_g_register(struct v4l2_subdev *sd, ++ struct v4l2_dbg_register *reg) +{ -+ struct max9286_priv *priv = v4l2_get_subdevdata(sd); -+ struct i2c_client *client = priv->client; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; -+ u8 val = 0; ++ u16 val = 0; + -+ ret = reg8_read(client, (u8)reg->reg, &val); ++ ret = reg16_read16(client, (u16)reg->reg, &val); + if (ret < 0) + return ret; + + reg->val = val; -+ reg->size = sizeof(u8); ++ reg->size = sizeof(u16); + + return 0; +} + -+static int max9286_s_register(struct v4l2_subdev *sd, -+ const struct v4l2_dbg_register *reg) ++static int ar0220_s_register(struct v4l2_subdev *sd, ++ const struct v4l2_dbg_register *reg) +{ -+ struct max9286_priv *priv = v4l2_get_subdevdata(sd); -+ struct i2c_client *client = priv->client; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); + -+ return reg8_write(client, (u8)reg->reg, (u8)reg->val); ++ return reg16_write16(client, (u16)reg->reg, (u16)reg->val); +} +#endif + -+static int max9286_s_power(struct v4l2_subdev *sd, int on) ++static struct v4l2_subdev_core_ops ar0220_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = ar0220_g_register, ++ .s_register = ar0220_s_register, ++#endif ++}; ++ ++static int ar0220_s_ctrl(struct v4l2_ctrl *ctrl) +{ -+ struct max9286_priv *priv = v4l2_get_subdevdata(sd); -+ struct i2c_client *client = priv->client; ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ar0220_priv *priv = to_ar0220(client); ++ int ret = -EINVAL; + -+ if (on) { -+ if (atomic_inc_return(&priv->use_count) == 1) -+ reg8_write(client, 0x69, priv->links_mask ^ 0x0f); /* unmask CSI forwarding from detected links */ -+ } else { -+ if (atomic_dec_return(&priv->use_count) == 0) -+ reg8_write(client, 0x69, 0x0f); /* mask CSI forwarding from all links */ ++ if (!priv->init_complete) ++ return 0; ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ case V4L2_CID_CONTRAST: ++ case V4L2_CID_SATURATION: ++ case V4L2_CID_HUE: ++ case V4L2_CID_GAMMA: ++ case V4L2_CID_SHARPNESS: ++ case V4L2_CID_AUTOGAIN: ++ case V4L2_CID_GAIN: ++ case V4L2_CID_EXPOSURE: ++ case V4L2_CID_HFLIP: ++ case V4L2_CID_VFLIP: ++ break; + } + -+ return 0; ++ return ret; +} + -+static int max9286_registered_async(struct v4l2_subdev *sd) -+{ -+ struct max9286_priv *priv = v4l2_get_subdevdata(sd); -+ struct i2c_client *client = priv->client; -+ int idx, tmp_addr; -+ -+ /* switch to GMSL serial_link for streaming video */ -+ tmp_addr = client->addr; -+ idx = sd->grp_id; -+ -+ client->addr = priv->des_addr; /* MAX9286 I2C */ -+ reg8_write(client, 0x0a, 0x11 << idx); /* enable reverse/forward control for CAMx */ -+ -+ client->addr = priv->max9271_addr_map[idx]; /* MAX9271-CAMx */ -+ reg8_write(client, 0x04, conf_link ? 0x43 : 0x83); /* enable serial_link */ -+ usleep_range(2000, 2500); /* wait 2ms after changing reverse_control */ -+ -+ client->addr = priv->des_addr; /* MAX9286 I2C */ -+ reg8_write(client, 0x0a, (priv->links_mask << 4) | priv->links_mask); /* enable reverse/forward control for all CAMs */ -+ -+ client->addr = tmp_addr; ++static const struct v4l2_ctrl_ops ar0220_ctrl_ops = { ++ .s_ctrl = ar0220_s_ctrl, ++}; + -+ return 0; -+} ++static struct v4l2_subdev_video_ops ar0220_video_ops = { ++ .s_stream = ar0220_s_stream, ++ .g_mbus_config = ar0220_g_mbus_config, ++}; + -+static struct v4l2_subdev_core_ops max9286_subdev_core_ops = { -+#ifdef CONFIG_VIDEO_ADV_DEBUG -+ .g_register = max9286_g_register, -+ .s_register = max9286_s_register, -+#endif -+ .s_power = max9286_s_power, -+ .registered_async = max9286_registered_async, ++static const struct v4l2_subdev_pad_ops ar0220_subdev_pad_ops = { ++ .get_edid = ar0220_get_edid, ++ .enum_mbus_code = ar0220_enum_mbus_code, ++ .get_selection = ar0220_get_selection, ++ .set_selection = ar0220_set_selection, ++ .get_fmt = ar0220_get_fmt, ++ .set_fmt = ar0220_set_fmt, +}; + -+static struct v4l2_subdev_ops max9286_subdev_ops = { -+ .core = &max9286_subdev_core_ops, ++static struct v4l2_subdev_ops ar0220_subdev_ops = { ++ .core = &ar0220_core_ops, ++ .video = &ar0220_video_ops, ++ .pad = &ar0220_subdev_pad_ops, +}; + -+static int max9286_parse_dt(struct i2c_client *client) ++static void ar0220_otp_id_read(struct i2c_client *client) +{ -+ struct max9286_priv *priv = i2c_get_clientdata(client); -+ struct device_node *np = client->dev.of_node; -+ struct device_node *endpoint = NULL; -+ struct property *prop; -+ int err, pwen, i; -+ int sensor_delay, gpio0 = 1, gpio1 = 1; -+ -+ u8 val = 0; -+ -+ if (of_property_read_u32(np, "maxim,links", &priv->links)) -+ priv->links = 4; -+ -+ if (of_property_read_u32(np, "maxim,lanes", &priv->lanes)) -+ priv->lanes = 4; -+ -+ pwen = of_get_gpio(np, 0); -+ if (pwen > 0) { -+ err = gpio_request_one(pwen, GPIOF_OUT_INIT_HIGH, dev_name(&client->dev)); -+ if (err) -+ dev_err(&client->dev, "cannot request PWEN gpio %d: %d\n", pwen, err); -+ } ++} + -+ mdelay(250); ++static ssize_t ar0220_otp_id_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev)); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ar0220_priv *priv = to_ar0220(client); + -+ reg8_read(client, 0x1e, &val); /* read max9286 ID */ -+ if (val != MAX9286_ID) { -+ prop = of_find_property(np, "reg", NULL); -+ if (prop) -+ of_remove_property(np, prop); -+ return -ENODEV; -+ } ++ return snprintf(buf, 32, "%02x:%02x:%02x:%02x:%02x:%02x\n", ++ priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); ++} + -+ if (!of_property_read_u32(np, "maxim,gpio0", &gpio0) || -+ !of_property_read_u32(np, "maxim,gpio1", &gpio1)) -+ reg8_write(client, 0x0f, 0x08 | (gpio1 << 1) | gpio0); ++static DEVICE_ATTR(otp_id_ar0220, S_IRUGO, ar0220_otp_id_show, NULL); + -+ if (of_property_read_u32(np, "maxim,resetb-gpio", &priv->gpio_resetb)) { -+ priv->gpio_resetb = -1; -+ } else { -+ if (of_property_read_bool(np, "maxim,resetb-active-high")) -+ priv->active_low_resetb = 0; -+ else -+ priv->active_low_resetb = 1; -+ } ++static int ar0220_initialize(struct i2c_client *client) ++{ ++ struct ar0220_priv *priv = to_ar0220(client); ++ u16 val = 0; ++ u16 pid = 0; ++ int ret = 0; + -+ if (!of_property_read_u32(np, "maxim,sensor_delay", &sensor_delay)) -+ mdelay(sensor_delay); -+ if (of_property_read_string(np, "maxim,fsync-mode", &priv->fsync_mode)) -+ priv->fsync_mode = fsync_mode_default; -+ if (of_property_read_u32(np, "maxim,fsync-period", &priv->fsync_period)) -+ priv->fsync_period = 3200000; /* 96MHz/30fps */ -+ priv->pclk_rising_edge = true; -+ if (of_property_read_bool(np, "maxim,pclk-falling-edge")) -+ priv->pclk_rising_edge = false; -+ if (of_property_read_u32(np, "maxim,timeout", &priv->timeout)) -+ priv->timeout = 100; -+ if (of_property_read_u32(np, "maxim,i2c-quirk", &priv->des_quirk_addr)) -+ priv->des_quirk_addr = 0; -+ if (of_property_read_u32(np, "maxim,him", &priv->him)) -+ priv->him = 0; -+ if (of_property_read_u32(np, "maxim,hsync", &priv->hsync)) -+ priv->hsync = 0; -+ if (of_property_read_u32(np, "maxim,vsync", &priv->vsync)) -+ priv->vsync = 1; -+ if (of_property_read_u32(np, "maxim,poc-delay", &priv->poc_delay)) -+ priv->poc_delay = 50; ++ /* check and show model ID */ ++ reg16_read16(client, AR0220_PID, &pid); + -+ /* module params override dts */ -+ if (him) -+ priv->him = him; -+ if (fsync_period) { -+ priv->fsync_period = fsync_period; -+ priv->fsync_mode = fsync_mode_default; ++ if (pid != AR0220_VERSION_REG) { ++ dev_dbg(&client->dev, "Product ID error %x\n", pid); ++ ret = -ENODEV; ++ goto err; + } -+ if (hsync) -+ priv->hsync = hsync; -+ if (!vsync) -+ priv->vsync = vsync; -+ if (gpio_resetb) -+ priv->gpio_resetb = gpio_resetb; -+ if (active_low_resetb) -+ priv->active_low_resetb = active_low_resetb; -+ if (poc_delay) -+ priv->poc_delay = poc_delay; -+ -+ for (i = 0; i < priv->links; i++) { -+ endpoint = of_graph_get_next_endpoint(np, endpoint); -+ if (!endpoint) -+ break; + -+ of_node_put(endpoint); ++ /* Program wizard registers */ ++ ar0220_set_regs(client, ar0220_regs_wizard, ARRAY_SIZE(ar0220_regs_wizard)); + -+ if (of_property_read_u32(endpoint, "max9271-addr", &priv->max9271_addr_map[i])) { -+ dev_err(&client->dev, "max9271-addr not set\n"); -+ return -EINVAL; -+ } ++ /* Enable stream */ ++ reg16_read16(client, 0x301a, &val); // read inital reset_register value ++ val |= (1 << 2); // Set streamOn bit ++ reg16_write16(client, 0x301a, val); // Start Streaming + -+ priv->sd_of_node[i] = endpoint; -+ } ++ /* Read OTP IDs */ ++ ar0220_otp_id_read(client); + -+ return 0; ++ dev_info(&client->dev, "ar0220 PID %x, res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n", ++ pid, AR0220_MAX_WIDTH, AR0220_MAX_HEIGHT, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); ++err: ++ return ret; +} + -+static void max9286_setup_remote_endpoint(struct i2c_client *client) ++static int ar0220_parse_dt(struct device_node *np, struct ar0220_priv *priv) +{ -+ struct max9286_priv *priv = i2c_get_clientdata(client); -+ struct device_node *np = client->dev.of_node; -+ struct device_node *endpoint = NULL, *rendpoint = NULL; ++ struct i2c_client *client = v4l2_get_subdevdata(&priv->sd); + int i; -+ struct property *csi_rate_prop, *dvp_order_prop; ++ struct device_node *endpoint = NULL, *rendpoint = NULL; ++ int tmp_addr = 0; + + for (i = 0; ; i++) { + endpoint = of_graph_get_next_endpoint(np, endpoint); @@ -2163,122 +1916,179 @@ index 0000000..989c782 + if (!rendpoint) + continue; + -+ csi_rate_prop = of_find_property(endpoint, "csi-rate", NULL); -+ if (csi_rate_prop) { -+ /* CSI2_RATE = PCLK*sizeof(YUV8)*links/lanes */ -+ priv->csi_rate = cpu_to_be32(100 * 8 * hweight8(priv->links_mask) / priv->lanes); -+ csi_rate_prop->value = &priv->csi_rate; -+ of_update_property(rendpoint, csi_rate_prop); -+ } ++ if (!of_property_read_u32(rendpoint, "ti9x3-addr", &priv->ti9x3_addr) && ++ !of_property_match_string(rendpoint->parent->parent, "compatible", "ti,ti9x4") && ++ !of_property_read_u32(rendpoint->parent->parent, "reg", &priv->ti9x4_addr) && ++ !kstrtouint(strrchr(rendpoint->full_name, '@') + 1, 0, &priv->port)) ++ break; ++ } + -+ dvp_order_prop = of_find_property(endpoint, "dvp-order", NULL); -+ if (dvp_order_prop) -+ of_update_property(rendpoint, dvp_order_prop); ++ if (!priv->ti9x4_addr) { ++ dev_err(&client->dev, "deserializer does not present\n"); ++ return -EINVAL; ++ } ++ ++ /* setup I2C translator address */ ++ tmp_addr = client->addr; ++ if (priv->ti9x4_addr) { ++ client->addr = priv->ti9x4_addr; /* Deserializer I2C address */ ++ ++ reg8_write(client, 0x4c, (priv->port << 4) | (1 << priv->port)); /* Select RX port number */ ++ usleep_range(2000, 2500); /* wait 2ms */ ++ reg8_write(client, 0x65, tmp_addr << 1); /* Sensor translated I2C address */ ++ reg8_write(client, 0x5d, AR0220_I2C_ADDR << 1); /* Sensor native I2C address */ ++ ++// reg8_write(client, 0x6e, 0xa9); /* GPIO0 - reset, GPIO1 - fsin */ + } ++ client->addr = tmp_addr; ++ ++ mdelay(10); ++ ++ return 0; +} + -+static int max9286_probe(struct i2c_client *client, -+ const struct i2c_device_id *did) ++static int ar0220_probe(struct i2c_client *client, ++ const struct i2c_device_id *did) +{ -+ struct max9286_priv *priv; -+ int err, i; -+ char supply_name[10]; ++ struct ar0220_priv *priv; ++ int ret; + + priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + -+ i2c_set_clientdata(client, priv); -+ priv->des_addr = client->addr; -+ priv->client = client; -+ atomic_set(&priv->use_count, 0); -+ priv->csi2_outord = 0xff; ++ v4l2_i2c_subdev_init(&priv->sd, client, &ar0220_subdev_ops); ++ priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; + -+ err = max9286_parse_dt(client); -+ if (err) -+ goto out; ++ priv->exposure = 0x100; ++ priv->gain = 0x100; ++ priv->autogain = 1; ++ v4l2_ctrl_handler_init(&priv->hdl, 4); ++ v4l2_ctrl_new_std(&priv->hdl, &ar0220_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 16, 1, 7); ++ v4l2_ctrl_new_std(&priv->hdl, &ar0220_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 16, 1, 7); ++ v4l2_ctrl_new_std(&priv->hdl, &ar0220_ctrl_ops, ++ V4L2_CID_SATURATION, 0, 7, 1, 2); ++ v4l2_ctrl_new_std(&priv->hdl, &ar0220_ctrl_ops, ++ V4L2_CID_HUE, 0, 23, 1, 12); ++ v4l2_ctrl_new_std(&priv->hdl, &ar0220_ctrl_ops, ++ V4L2_CID_GAMMA, -128, 128, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &ar0220_ctrl_ops, ++ V4L2_CID_SHARPNESS, 0, 10, 1, 3); ++ v4l2_ctrl_new_std(&priv->hdl, &ar0220_ctrl_ops, ++ V4L2_CID_AUTOGAIN, 0, 1, 1, priv->autogain); ++ v4l2_ctrl_new_std(&priv->hdl, &ar0220_ctrl_ops, ++ V4L2_CID_GAIN, 0, 0xffff, 1, priv->gain); ++ v4l2_ctrl_new_std(&priv->hdl, &ar0220_ctrl_ops, ++ V4L2_CID_EXPOSURE, 0, 0xffff, 1, priv->exposure); ++ v4l2_ctrl_new_std(&priv->hdl, &ar0220_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 1); ++ v4l2_ctrl_new_std(&priv->hdl, &ar0220_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ priv->sd.ctrl_handler = &priv->hdl; + -+ for (i = 0; i < 4; i++) { -+ sprintf(supply_name, "POC%d", i); -+ priv->poc_supply[i] = devm_regulator_get_optional(&client->dev, supply_name); -+ } ++ ret = priv->hdl.error; ++ if (ret) ++ goto cleanup; + -+ err = max9286_initialize(client); -+ if (err < 0) -+ goto out; ++ v4l2_ctrl_handler_setup(&priv->hdl); + -+ max9286_setup_remote_endpoint(client); ++ priv->pad.flags = MEDIA_PAD_FL_SOURCE; ++ priv->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR; ++ ret = media_entity_pads_init(&priv->sd.entity, 1, &priv->pad); ++ if (ret < 0) ++ goto cleanup; + -+ for (i = 0; i < 4; i++) { -+ v4l2_subdev_init(&priv->sd[i], &max9286_subdev_ops); -+ priv->sd[i].owner = client->dev.driver->owner; -+ priv->sd[i].dev = &client->dev; -+ priv->sd[i].grp_id = i; -+ v4l2_set_subdevdata(&priv->sd[i], priv); -+ priv->sd[i].of_node = priv->sd_of_node[i]; ++ ret = ar0220_parse_dt(client->dev.of_node, priv); ++ if (ret) ++ goto cleanup; + -+ snprintf(priv->sd[i].name, V4L2_SUBDEV_NAME_SIZE, "%s.%d %d-%04x", -+ client->dev.driver->name, i, i2c_adapter_id(client->adapter), -+ client->addr); ++ ret = ar0220_initialize(client); ++ if (ret < 0) ++ goto cleanup; + -+ err = v4l2_async_register_subdev(&priv->sd[i]); -+ if (err < 0) -+ goto out; -+ } -+out: -+ return err; -+} ++ priv->rect.left = 0; ++ priv->rect.top = 0; ++ priv->rect.width = AR0220_MAX_WIDTH; ++ priv->rect.height = AR0220_MAX_HEIGHT; + -+static int max9286_remove(struct i2c_client *client) -+{ -+ struct max9286_priv *priv = i2c_get_clientdata(client); -+ int i; ++ ret = v4l2_async_register_subdev(&priv->sd); ++ if (ret) ++ goto cleanup; + -+ for (i = 0; i < 4; i++) { -+ v4l2_async_unregister_subdev(&priv->sd[i]); -+ v4l2_device_unregister_subdev(&priv->sd[i]); ++ if (device_create_file(&client->dev, &dev_attr_otp_id_ar0220) != 0) { ++ dev_err(&client->dev, "sysfs otp_id entry creation failed\n"); ++ goto cleanup; + } + ++ priv->init_complete = 1; ++ + return 0; ++ ++cleanup: ++ media_entity_cleanup(&priv->sd.entity); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ v4l2_device_unregister_subdev(&priv->sd); ++#ifdef CONFIG_SOC_CAMERA_AR0220 ++ v4l_err(client, "failed to probe @ 0x%02x (%s)\n", ++ client->addr, client->adapter->name); ++#endif ++ return ret; +} + -+static const struct of_device_id max9286_dt_ids[] = { -+ { .compatible = "maxim,max9286" }, -+ {}, ++static int ar0220_remove(struct i2c_client *client) ++{ ++ struct ar0220_priv *priv = i2c_get_clientdata(client); ++ ++ device_remove_file(&client->dev, &dev_attr_otp_id_ar0220); ++ v4l2_async_unregister_subdev(&priv->sd); ++ media_entity_cleanup(&priv->sd.entity); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ v4l2_device_unregister_subdev(&priv->sd); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_SOC_CAMERA_AR0220 ++static const struct i2c_device_id ar0220_id[] = { ++ { "ar0220", 0 }, ++ { } +}; -+MODULE_DEVICE_TABLE(of, max9286_dt_ids); ++MODULE_DEVICE_TABLE(i2c, ar0220_id); + -+static const struct i2c_device_id max9286_id[] = { -+ { "max9286", 0 }, ++static const struct of_device_id ar0220_of_ids[] = { ++ { .compatible = "aptina,ar0220", }, + { } +}; -+MODULE_DEVICE_TABLE(i2c, max9286_id); ++MODULE_DEVICE_TABLE(of, ar0220_of_ids); + -+static struct i2c_driver max9286_i2c_driver = { ++static struct i2c_driver ar0220_i2c_driver = { + .driver = { -+ .name = "max9286", -+ .of_match_table = of_match_ptr(max9286_dt_ids), ++ .name = "ar0220", ++ .of_match_table = ar0220_of_ids, + }, -+ .probe = max9286_probe, -+ .remove = max9286_remove, -+ .id_table = max9286_id, ++ .probe = ar0220_probe, ++ .remove = ar0220_remove, ++ .id_table = ar0220_id, +}; + -+module_i2c_driver(max9286_i2c_driver); ++module_i2c_driver(ar0220_i2c_driver); + -+MODULE_DESCRIPTION("GMSL driver for MAX9286"); ++MODULE_DESCRIPTION("SoC Camera driver for AR0220"); +MODULE_AUTHOR("Vladimir Barinov"); +MODULE_LICENSE("GPL"); -diff --git a/drivers/media/i2c/soc_camera/max9286.h b/drivers/media/i2c/soc_camera/max9286.h ++#endif +diff --git a/drivers/media/i2c/soc_camera/ar0220.h b/drivers/media/i2c/soc_camera/ar0220.h new file mode 100644 -index 0000000..6c2a9e0 +index 0000000..29987a6 --- /dev/null -+++ b/drivers/media/i2c/soc_camera/max9286.h -@@ -0,0 +1,244 @@ ++++ b/drivers/media/i2c/soc_camera/ar0220.h +@@ -0,0 +1,43 @@ +/* -+ * MAXIM max9286-max9271 GMSL driver include file ++ * ON Semiconductor AR0220 sensor camera wizard 1820x940@44/RCCB/BT656 + * -+ * Copyright (C) 2015-2017 Cogent Embedded, Inc. ++ * Copyright (C) 2017 Cogent Embedded, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the @@ -2286,1012 +2096,999 @@ index 0000000..6c2a9e0 + * option) any later version. + */ + -+#ifndef _MAX9286_MAX9271_H -+#define _MAX9286_MAX9271_H ++//#define AR0220_DISPLAY_PATTERN_FIXED ++//#define AR0220_DISPLAY_PATTERN_COLOR_BAR + -+//#define DEBUG -+#ifdef DEBUG -+//#define WRITE_VERIFY -+#define MAXIM_DUMP -+#undef dev_dbg -+#define dev_dbg dev_info -+#endif ++#define AR0220_MAX_WIDTH 3648 // (1820*2=3640) <- must be multiple of 16 - requred by R-CAR VIN ++#define AR0220_MAX_HEIGHT 944 + -+#define REG8_NUM_RETRIES 1 /* number of read/write retries */ -+#define REG16_NUM_RETRIES 10 /* number of read/write retries */ -+#define MAX9271_ID 0x9 -+#define MAX96705_ID 0x41 -+#define MAX9286_ID 0x40 -+#define BROADCAST 0x6f ++#define AR0220_DELAY 0xffff + -+static inline int reg8_read(struct i2c_client *client, u8 reg, u8 *val) -+{ -+ int ret, retries; ++struct ar0220_reg { ++ u16 reg; ++ u16 val; ++}; + -+ for (retries = REG8_NUM_RETRIES; retries; retries--) { -+ ret = i2c_smbus_read_byte_data(client, reg); -+ if (!(ret < 0)) -+ break; -+ } ++static const struct ar0220_reg ar0220_regs_wizard[] = { ++{0x301A, 0x0018}, // RESET_REGISTER ++{AR0220_DELAY, 500}, // Wait 500ms ++{0x3070, 0x0000}, // 1: Solid color test pattern, ++ // 2: Full color bar test pattern, ++ // 3: Fade to grey color bar test pattern, ++ //256: Walking 1 test pattern (12 bit) ++{0x3072, 0x0123}, // R ++{0x3074, 0x0456}, // G(GR row) ++{0x3076, 0x0abc}, // B ++{0x3078, 0x0def}, // G(GB row) ++#ifdef AR0220_DISPLAY_PATTERN_FIXED ++{0x3070, 0x0001}, ++#endif ++#ifdef AR0220_DISPLAY_PATTERN_COLOR_BAR ++{0x3070, 0x0002}, ++#endif ++{AR0220_DELAY, 100}, // Wait 100ms ++}; +diff --git a/drivers/media/i2c/soc_camera/max9286.c b/drivers/media/i2c/soc_camera/max9286.c +new file mode 100644 +index 0000000..4dd80f5 +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/max9286.c +@@ -0,0 +1,697 @@ ++/* ++ * MAXIM max9286 GMSL driver ++ * ++ * Copyright (C) 2015-2018 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ + -+ if (ret < 0) { -+ dev_dbg(&client->dev, -+ "read fail: chip 0x%x register 0x%x: %d\n", -+ client->addr, reg, ret); -+ } else { -+ *val = ret; -+ } ++#include ++#include ++#include ++#include ++#include ++#include ++#include + -+ return ret < 0 ? ret : 0; -+} ++#include ++#include ++#include ++#include + -+static inline int reg8_write(struct i2c_client *client, u8 reg, u8 val) -+{ -+ int ret, retries; ++#include "max9286.h" + -+ for (retries = REG8_NUM_RETRIES; retries; retries--) { -+ ret = i2c_smbus_write_byte_data(client, reg, val); -+ if (!(ret < 0)) -+ break; -+ } ++#define MAXIM_I2C_I2C_SPEED_837KHZ (0x7 << 2) /* 837kbps */ ++#define MAXIM_I2C_I2C_SPEED_533KHZ (0x6 << 2) /* 533kbps */ ++#define MAXIM_I2C_I2C_SPEED_339KHZ (0x5 << 2) /* 339 kbps */ ++#define MAXIM_I2C_I2C_SPEED_173KHZ (0x4 << 2) /* 174kbps */ ++#define MAXIM_I2C_I2C_SPEED_105KHZ (0x3 << 2) /* 105 kbps */ ++#define MAXIM_I2C_I2C_SPEED_085KHZ (0x2 << 2) /* 84.7 kbps */ ++#define MAXIM_I2C_I2C_SPEED_028KHZ (0x1 << 2) /* 28.3 kbps */ ++#define MAXIM_I2C_I2C_SPEED MAXIM_I2C_I2C_SPEED_339KHZ + -+ if (ret < 0) { -+ dev_dbg(&client->dev, -+ "write fail: chip 0x%x register 0x%x: %d\n", -+ client->addr, reg, ret); -+ } else { -+#ifdef WRITE_VERIFY -+ u8 val2; -+ reg8_read(client, reg, &val2); -+ if (val != val2) -+ dev_err(&client->dev, -+ "write verify mismatch: chip 0x%x reg=0x%x " -+ "0x%x->0x%x\n", client->addr, reg, val, val2); -+#endif -+ } ++struct max9286_priv { ++ struct v4l2_subdev sd[4]; ++ struct device_node *sd_of_node[4]; ++ int des_addr; ++ int des_quirk_addr; /* second MAX9286 on the same I2C bus */ ++ int links; ++ int links_mask; ++ int lanes; ++ int csi_rate; ++ const char *fsync_mode; ++ int fsync_period; ++ char pclk_rising_edge; ++ int gpio_resetb; ++ int active_low_resetb; ++ int him; ++ int hsync; ++ int vsync; ++ int timeout; ++ int poc_delay; ++ atomic_t use_count; ++ u32 csi2_outord; ++ struct i2c_client *client; ++ int max9271_addr_map[4]; ++ int ser_id; ++ struct regulator *poc_supply[4]; /* PoC power supply */ ++}; + -+ return ret < 0 ? ret : 0; -+} ++static char fsync_mode_default[20] = "manual"; /* manual, automatic, semi-automatic, external */ + -+static inline int reg16_read(struct i2c_client *client, u16 reg, u8 *val) -+{ -+ int ret, retries; -+ u8 buf[2] = {reg >> 8, reg & 0xff}; ++static int conf_link; ++module_param(conf_link, int, 0644); ++MODULE_PARM_DESC(conf_link, " Force configuration link. Used only if robust firmware flashing required (f.e. recovery)"); + -+ for (retries = REG16_NUM_RETRIES; retries; retries--) { -+ ret = i2c_master_send(client, buf, 2); -+ if (ret == 2) { -+ ret = i2c_master_recv(client, buf, 1); -+ if (ret == 1) -+ break; -+ } -+ } ++static int poc_trig; ++module_param(poc_trig, int, 0644); ++MODULE_PARM_DESC(poc_trig, " Use PoC triggering during reverse channel setup. Useful on systems with dedicated PoC and unstable ser-des lock"); + -+ if (ret < 0) { -+ dev_dbg(&client->dev, -+ "read fail: chip 0x%x register 0x%x: %d\n", -+ client->addr, reg, ret); -+ } else { -+ *val = buf[0]; -+ } ++static int him; ++module_param(him, int, 0644); ++MODULE_PARM_DESC(him, " Use High-Immunity mode (default: leagacy mode)"); + -+ return ret < 0 ? ret : 0; -+} ++static int fsync_period; ++module_param(fsync_period, int, 0644); ++MODULE_PARM_DESC(fsync_period, " Frame sync period (default: 3.2MHz)"); + -+static inline int reg16_write(struct i2c_client *client, u16 reg, u8 val) -+{ -+ int ret, retries; -+ u8 buf[3] = {reg >> 8, reg & 0xff, val}; ++static int hsync; ++module_param(hsync, int, 0644); ++MODULE_PARM_DESC(hsync, " HSYNC invertion (default: 0 - not inverted)"); + -+ for (retries = REG16_NUM_RETRIES; retries; retries--) { -+ ret = i2c_master_send(client, buf, 3); -+ if (ret == 3) -+ break; -+ } ++static int vsync = 1; ++module_param(vsync, int, 0644); ++MODULE_PARM_DESC(vsync, " VSYNC invertion (default: 1 - inverted)"); + -+ if (ret < 0) { -+ dev_dbg(&client->dev, -+ "write fail: chip 0x%x register 0x%x: %d\n", -+ client->addr, reg, ret); -+ } else { -+#ifdef WRITE_VERIFY -+ u8 val2; -+ reg16_read(client, reg, &val2); -+ if (val != val2) -+ dev_err(&client->dev, -+ "write verify mismatch: chip 0x%x reg=0x%x " -+ "0x%x->0x%x\n", client->addr, reg, val, val2); -+#endif -+ } ++static int gpio_resetb; ++module_param(gpio_resetb, int, 0644); ++MODULE_PARM_DESC(gpio_resetb, " Serializer GPIO reset (default: 0 - not used)"); + -+ return ret < 0 ? ret : 0; -+} ++static int active_low_resetb; ++module_param(active_low_resetb, int, 0644); ++MODULE_PARM_DESC(active_low_resetb, " Serializer GPIO reset level (default: 0 - active high)"); + ++static int poc_delay; ++module_param(poc_delay, int, 0644); ++MODULE_PARM_DESC(poc_delay, " Delay in ms after POC enable (default: 0 ms)"); + -+static inline int reg16_read16(struct i2c_client *client, u16 reg, u16 *val) ++static char* ser_name(int id) +{ -+ int ret, retries; -+ u8 buf[2] = {reg >> 8, reg & 0xff}; -+ -+ for (retries = REG8_NUM_RETRIES; retries; retries--) { -+ ret = i2c_master_send(client, buf, 2); -+ if (ret == 2) { -+ ret = i2c_master_recv(client, buf, 2); -+ if (ret == 2) -+ break; -+ } -+ } -+ -+ if (ret < 0) { -+ dev_err(&client->dev, -+ "read fail: chip 0x%x register 0x%x: %d\n", -+ client->addr, reg, ret); -+ } else { -+ *val = ((u16)buf[0] << 8) | buf[1]; ++ switch (id) { ++ case MAX9271_ID: ++ return "MAX9271"; ++ case MAX96705_ID: ++ return "MAX96705"; ++ default: ++ return "unknown"; + } -+ -+ return ret < 0 ? ret : 0; +} + -+static inline int reg16_write16(struct i2c_client *client, u16 reg, u16 val) ++static void max9286_preinit(struct i2c_client *client, int addr) +{ -+ int ret, retries; -+ u8 buf[4] = {reg >> 8, reg & 0xff, val >> 8, val & 0xff}; -+ -+ for (retries = REG8_NUM_RETRIES; retries; retries--) { -+ ret = i2c_master_send(client, buf, 4); -+ if (ret == 4) -+ break; -+ } -+ -+ if (ret < 0) { -+ dev_err(&client->dev, -+ "write fail: chip 0x%x register 0x%x: %d\n", -+ client->addr, reg, ret); -+ } ++ struct max9286_priv *priv = i2c_get_clientdata(client); + -+ return ret < 0 ? ret : 0; ++ client->addr = addr; /* MAX9286-CAMx I2C */ ++ reg8_write(client, 0x0a, 0x00); /* disable reverse control for all cams */ ++ reg8_write(client, 0x00, 0x00); /* disable all GMSL links [0:3] */ ++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ ++ reg8_write(client, 0x1c, priv->him ? 0xf4 : 0x04); /* high-immunity or legacy mode */ +} + -+ -+#ifdef MAXIM_DUMP -+static void maxim_ovsensor_dump_regs(struct i2c_client *client) ++static void max9286_sensor_reset(struct i2c_client *client, int addr, int reset_on) +{ -+ int ret, i; -+ u8 val = 0; -+ u16 regs[] = {0x300a, 0x300b, 0x300c}; ++ struct max9286_priv *priv = i2c_get_clientdata(client); + -+ dev_dbg(&client->dev, "dump regs 0x%x\n", client->addr); ++ if (priv->gpio_resetb < 1 || priv->gpio_resetb > 5) ++ return; + -+ for (i = 0; i < sizeof(regs) / 2; i++) { -+ ret = reg16_read(client, regs[i], &val); -+ if (ret < 0) -+ dev_err(&client->dev, -+ "read fail: chip 0x%x register 0x%02x: %d\n", -+ client->addr, regs[i], ret); -+ printk("0x%02x -> 0x%x\n", regs[i], val); -+ } ++ /* sensor reset/unreset */ ++ client->addr = addr; /* MAX9271-CAMx I2C */ ++ reg8_write(client, 0x0f, (0xfe & ~BIT(priv->gpio_resetb)) | /* set GPIOn value to reset/unreset */ ++ ((priv->active_low_resetb ? BIT(priv->gpio_resetb) : 0) ^ reset_on)); ++ reg8_write(client, 0x0e, 0x42 | BIT(priv->gpio_resetb)); /* set GPIOn direction output */ +} + -+static void maxim_ov10635_dump_format_regs(struct i2c_client *client) ++static void max9286_postinit(struct i2c_client *client, int addr) +{ -+ int ret, i; -+ u8 val; -+ u16 regs[] = {0x3003, 0x3004, 0x4300, -+ 0x4605, 0x3621, 0x3702, 0x3703, 0x3704, -+ 0x3802, 0x3803, 0x3806, 0x3807, 0x3808, 0x3809, 0x380a, -+ 0x380b, 0x380c, 0x380d, 0x380e, 0x380f, -+ 0x4606, 0x4607, 0x460a, 0x460b, -+ 0xc488, 0xc489, 0xc48a, 0xc48b, -+ 0xc4cc, 0xc4cd, 0xc4ce, 0xc4cf, 0xc512, 0xc513, -+ 0xc518, 0xc519, 0xc51a, 0xc51b, -+ }; ++ struct max9286_priv *priv = i2c_get_clientdata(client); ++ int idx; + -+ dev_dbg(&client->dev, "dump regs 0x%x\n", client->addr); ++ for (idx = 0; idx < priv->links; idx++) { ++ client->addr = priv->des_addr; /* MAX9286 I2C */ ++ reg8_write(client, 0x0a, 0x11 << idx); /* enable reverse/forward control for CAMx */ + -+ for (i = 0; i < sizeof(regs) / 2; i++) { -+ ret = reg16_read(client, regs[i], &val); -+ if (ret < 0) -+ dev_err(&client->dev, -+ "read fail: chip 0x%x register 0x%02x: %d\n", -+ client->addr, regs[i], ret); -+ printk("0x%02x -> 0x%x\n", regs[i], val); ++ client->addr = priv->max9271_addr_map[idx]; /* MAX9271-CAMx I2C */ ++ max9286_sensor_reset(client, client->addr, 0); /* sensor unreset */ + } -+} + -+static void maxim_max927x_dump_regs(struct i2c_client *client) -+{ -+ int ret; -+ u8 reg; -+ -+ dev_dbg(&client->dev, "dump regs 0x%x\n", client->addr); ++ client->addr = addr; /* MAX9286 I2C */ ++ reg8_write(client, 0x0a, 0x00); /* disable reverse control for all cams */ ++ reg8_write(client, 0x00, 0xe0 | priv->links_mask); /* enable GMSL link for CAMs */ ++ reg8_write(client, 0x0b, priv->csi2_outord); /* CSI2 output order */ ++ reg8_write(client, 0x15, 0x9b); /* enable CSI output, VC is set accordingly to Link number, BIT7 magic must be set */ ++ reg8_write(client, 0x1b, priv->links_mask); /* enable equalizer for CAMs */ ++ usleep_range(5000, 5500); /* wait 2ms after any change of reverse channel settings */ + -+ for (reg = 0; reg < 0x20; reg++) { -+ ret = i2c_smbus_read_byte_data(client, reg); -+ if (ret < 0) -+ dev_err(&client->dev, -+ "read fail: chip 0x%x register 0x%x: %d\n", -+ client->addr, reg, ret); -+ printk("0x%02x ", ret); -+ if (((reg + 1) % 0x10) == 0) -+ printk("\n"); ++ if (strcmp(priv->fsync_mode, "manual") == 0) { ++ reg8_write(client, 0x01, 0x00); /* manual: FRAMESYNC set manually via [0x06:0x08] regs */ ++ } else if (strcmp(priv->fsync_mode, "automatic") == 0) { ++ reg8_write(client, 0x01, 0x02); /* automatic: FRAMESYNC taken from the slowest Link */ ++ } else if (strcmp(priv->fsync_mode, "semi-automatic") == 0) { ++ reg8_write(client, 0x01, 0x01); /* semi-automatic: FRAMESYNC taken from the slowest Link */ ++ } else if (strcmp(priv->fsync_mode, "external") == 0) { ++ reg8_write(client, 0x01, 0xc0); /* ECU (aka MCU) based FrameSync using GPI-to-GPO */ + } +} -+#endif /* MAXIM_DUMP */ -+#endif /* _MAX9286_MAX9271_H */ -diff --git a/drivers/media/i2c/soc_camera/ov10635.c b/drivers/media/i2c/soc_camera/ov10635.c -new file mode 100644 -index 0000000..8c06e59 ---- /dev/null -+++ b/drivers/media/i2c/soc_camera/ov10635.c -@@ -0,0 +1,759 @@ -+/* -+ * OmniVision ov10635 sensor camera driver -+ * -+ * Copyright (C) 2015-2017 Cogent Embedded, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2 of the License, or (at your -+ * option) any later version. -+ */ + -+#include -+#include -+#include -+#include -+#include ++static int max9286_reverse_channel_setup(struct i2c_client *client, int idx) ++{ ++ struct max9286_priv *priv = i2c_get_clientdata(client); ++ u8 val = 0; ++ int timeout = priv->timeout; ++ char timeout_str[10]; ++ int ret = 0; + -+#include -+#include -+#include -+#include ++ /* Reverse channel enable */ ++ client->addr = priv->des_addr; /* MAX9286-CAMx I2C */ ++ reg8_write(client, 0x3f, 0x4f); /* enable custom reverse channel & first pulse length */ ++ reg8_write(client, 0x34, 0xa2 | MAXIM_I2C_I2C_SPEED); /* enable artificial ACKs, I2C speed set */ ++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ ++ reg8_write(client, 0x00, 0xe0 | BIT(idx)); /* enable GMSL link for CAMx */ ++ reg8_write(client, 0x0a, 0x11 << idx); /* enable reverse control for CAMx */ ++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ + -+#include "max9286.h" -+#include "ov10635.h" ++ for (;;) { ++ client->addr = priv->des_addr; /* MAX9286-CAMx I2C */ ++ reg8_write(client, 0x3b, 0x1e); /* first pulse length rise time changed from 300ns to 200ns, amplitude 100mV */ ++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ + -+#define OV10635_I2C_ADDR 0x30 ++ client->addr = 0x40; /* MAX9271-CAMx I2C */ ++ reg8_write(client, 0x04, 0x43); /* wake-up, enable reverse_control/conf_link */ ++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ ++ reg8_write(client, 0x08, 0x01); /* reverse channel receiver high threshold enable */ ++ reg8_write(client, 0x97, priv->him ? 0xaf : 0x5f); /* enable reverse control channel programming (MAX96705-MAX96711 only) */ ++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ + -+#define OV10635_PID 0x300a -+#define OV10635_VER 0x300b -+#define OV10635_VERSION_REG 0xa635 -+#define OV10635_VERSION(pid, ver) (((pid) << 8) | ((ver) & 0xff)) ++ client->addr = priv->des_addr; /* MAX9286-CAMx I2C */ ++ reg8_write(client, 0x3b, 0x19); /* reverse channel increase amplitude 170mV to compensate high threshold enabled */ ++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ + -+struct ov10635_priv { -+ struct v4l2_subdev sd; -+ struct v4l2_ctrl_handler hdl; -+ struct media_pad pad; -+ struct v4l2_rect rect; -+ int subsampling; -+ int fps_denominator; -+ int init_complete; -+ u8 id[6]; -+ int dvp_order; -+ /* serializers */ -+ int max9286_addr; -+ int max9271_addr; -+ int ti964_addr; -+ int ti954_addr; -+ int ti9x3_addr; -+ int port; -+ int gpio_resetb; -+ int gpio_fsin; -+}; ++ client->addr = 0x40; /* MAX9271-CAMx I2C */ ++ reg8_read(client, 0x1e, &val); /* read max9271 ID */ ++ if (val == MAX9271_ID || val == MAX96705_ID || --timeout == 0) { ++ priv->ser_id = val; ++ break; ++ } + -+static inline struct ov10635_priv *to_ov10635(const struct i2c_client *client) -+{ -+ return container_of(i2c_get_clientdata(client), struct ov10635_priv, sd); -+} ++ /* Check if already initialized (after reboot/reset ?) */ ++ client->addr = priv->max9271_addr_map[idx]; /* MAX9271-CAMx I2C */ ++ reg8_read(client, 0x1e, &val); /* read max9271 ID */ ++ if (val == MAX9271_ID || val == MAX96705_ID) { ++ priv->ser_id = val; ++ reg8_write(client, 0x04, 0x43); /* enable reverse_control/conf_link */ ++ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */ ++ ret = -EADDRINUSE; ++ break; ++ } + -+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) -+{ -+ return &container_of(ctrl->handler, struct ov10635_priv, hdl)->sd; -+} ++ if (timeout == priv->timeout / 2 && poc_trig) { ++ if (!IS_ERR(priv->poc_supply[idx])) { ++ if (regulator_disable(priv->poc_supply[idx])) ++ dev_err(&client->dev, "fail to disable POC%d regulator\n", idx); ++ mdelay(200); ++ if (regulator_enable(priv->poc_supply[idx])) ++ dev_err(&client->dev, "fail to enable POC%d regulator\n", idx); ++ mdelay(priv->poc_delay); ++ } ++ } ++ } + -+static void ov10635_s_port(struct i2c_client *client, int fwd_en) -+{ -+ struct ov10635_priv *priv = to_ov10635(client); -+ int tmp_addr; ++ max9286_sensor_reset(client, client->addr, 1); /* sensor reset */ + -+ if (priv->max9286_addr) { -+ tmp_addr = client->addr; -+ client->addr = priv->max9286_addr; /* Deserializer I2C address */ -+ reg8_write(client, 0x0a, fwd_en ? 0x11 << priv->port : 0); /* Enable/disable reverse/forward control for this port */ -+ usleep_range(5000, 5500); /* wait 5ms */ -+ client->addr = tmp_addr; -+ }; ++ if (!timeout) { ++ ret = -ETIMEDOUT; ++ goto out; ++ } ++ ++ priv->links_mask |= BIT(idx); ++ priv->csi2_outord &= ~(0x3 << (idx * 2)); ++ priv->csi2_outord |= ((hweight8(priv->links_mask) - 1) << (idx * 2)); ++ ++out: ++ sprintf(timeout_str, "retries=%d", priv->timeout - timeout); ++ dev_info(&client->dev, "link%d %s %sat 0x%x %s %s\n", idx, ser_name(priv->ser_id), ++ ret == -EADDRINUSE ? "already " : "", priv->max9271_addr_map[idx], ++ ret == -ETIMEDOUT ? "not found: timeout GMSL link establish" : "", ++ priv->timeout - timeout? timeout_str : ""); ++ ++ return ret; +} + -+static int ov10635_set_regs(struct i2c_client *client, -+ const struct ov10635_reg *regs, int nr_regs) ++static void max9286_initial_setup(struct i2c_client *client) +{ -+ int i; ++ struct max9286_priv *priv = i2c_get_clientdata(client); + -+ for (i = 0; i < nr_regs; i++) { -+ if (reg16_write(client, regs[i].reg, regs[i].val)) { -+ usleep_range(100, 150); /* wait 100ns */ -+ reg16_write(client, regs[i].reg, regs[i].val); -+ } ++ /* Initial setup */ ++ client->addr = priv->des_addr; /* MAX9286-CAMx I2C */ ++ reg8_write(client, 0x15, 0x13); /* disable CSI output, VC is set accordingly to Link number */ ++ reg8_write(client, 0x69, 0x0f); /* mask CSI forwarding from all links */ ++ switch (priv->lanes) { ++ case 1: ++ reg8_write(client, 0x12, 0x33); /* enable CSI-2 Lane D0, DBL mode, YUV422 8-bit*/ ++ break; ++ case 2: ++ reg8_write(client, 0x12, 0x73); /* enable CSI-2 Lanes D0,D1, DBL mode, YUV422 8-bit*/ ++ break; ++ case 3: ++ reg8_write(client, 0x12, 0xd3); /* enable CSI-2 Lanes D0-D2, DBL mode, YUV422 8-bit*/ ++ break; ++ case 4: ++ reg8_write(client, 0x12, 0xf3); /* enable CSI-2 Lanes D0-D3, DBL mode, YUV422 8-bit*/ ++ break; ++ default: ++ dev_err(&client->dev, "CSI2 lanes number is invalid (%d)\n", priv->lanes); + } + -+ return 0; -+} ++ /* Start GMSL initialization with FSYNC disabled. This is required for some odd LVDS cameras */ ++ reg8_write(client, 0x01, 0xc0); /* ECU (aka MCU) based FrameSync using GPI-to-GPO */ ++ reg8_write(client, 0x06, priv->fsync_period & 0xff); ++ reg8_write(client, 0x07, (priv->fsync_period >> 8) & 0xff); ++ reg8_write(client, 0x08, priv->fsync_period >> 16); + -+static int ov10635_s_stream(struct v4l2_subdev *sd, int enable) -+{ -+ return 0; ++ reg8_write(client, 0x63, 0); /* disable overlap window */ ++ reg8_write(client, 0x64, 0); ++ reg8_write(client, 0x0c, 0x91 | (priv->vsync ? BIT(3) : 0) | (priv->hsync ? BIT(2) : 0)); /* enable HS/VS encoding, use D14/15 for HS/VS, invert HS/VS */ ++ reg8_write(client, 0x19, 0x0c); /* Drive HSTRAIL state for 120ns after the last payload bit */ +} + -+static int ov10635_set_window(struct v4l2_subdev *sd, int subsampling) ++static void max9286_gmsl_link_setup(struct i2c_client *client, int idx) +{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ struct ov10635_priv *priv = to_ov10635(client); ++ struct max9286_priv *priv = i2c_get_clientdata(client); + -+ /* disable clocks */ -+ reg16_write(client, 0x302e, 0x00); -+ reg16_write(client, 0x301b, 0xff); -+ reg16_write(client, 0x301c, 0xff); -+ reg16_write(client, 0x301a, 0xff); ++ /* GMSL setup */ ++ client->addr = 0x40; /* MAX9271-CAMx I2C */ ++ reg8_write(client, 0x0d, 0x22 | MAXIM_I2C_I2C_SPEED); /* disable artificial ACK, I2C speed set */ ++ reg8_write(client, 0x07, 0x84 | (priv->pclk_rising_edge ? 0 : 0x10)); /* RAW/YUV, PCLK edge, HS/VS encoding enabled */ ++ usleep_range(2000, 2500); /* wait 2ms */ ++ reg8_write(client, 0x02, 0xff); /* spread spectrum +-4%, pclk range automatic, Gbps automatic */ ++ usleep_range(2000, 2500); /* wait 2ms */ + -+ /* setup resolution */ -+ reg16_write(client, 0x3808, priv->rect.width >> 8); -+ reg16_write(client, 0x3809, priv->rect.width & 0xff); -+ reg16_write(client, 0x380a, priv->rect.height >> 8); -+ reg16_write(client, 0x380b, priv->rect.height & 0xff); ++ if (priv->ser_id == MAX96705_ID) { ++ /* setup crossbar in DBL mode: reverse DVP bus */ ++ reg8_write(client, 0x20, 0x07); ++ reg8_write(client, 0x21, 0x06); ++ reg8_write(client, 0x22, 0x05); ++ reg8_write(client, 0x23, 0x04); ++ reg8_write(client, 0x24, 0x03); ++ reg8_write(client, 0x25, 0x02); ++ reg8_write(client, 0x26, 0x01); ++ reg8_write(client, 0x27, 0x00); + -+ /* enable/disable subsampling */ -+ reg16_write(client, 0x5005, subsampling ? 0x89 : 0x08); -+ reg16_write(client, 0x3007, subsampling ? 0x02 : 0x01); -+ reg16_write(client, 0x4004, subsampling ? 0x02 : 0x04); ++ reg8_write(client, 0x30, 0x17); ++ reg8_write(client, 0x31, 0x16); ++ reg8_write(client, 0x32, 0x15); ++ reg8_write(client, 0x33, 0x14); ++ reg8_write(client, 0x34, 0x13); ++ reg8_write(client, 0x35, 0x12); ++ reg8_write(client, 0x36, 0x11); ++ reg8_write(client, 0x37, 0x10); ++ } + -+#if 0 /* This is implemented in VIN via SOC_CAMERA layer, hence skip */ -+ /* horiz crop start */ -+ reg16_write(client, 0x3800, priv->rect.left >> 8); -+ reg16_write(client, 0x3801, priv->rect.left & 0xff); -+ /* horiz crop end */ -+ reg16_write(client, 0x3804, (priv->rect.left + priv->rect.width + 1) >> 8); -+ reg16_write(client, 0x3805, (priv->rect.left + priv->rect.width + 1) & 0xff); -+ /* vert crop start */ -+ reg16_write(client, 0x3802, priv->rect.top >> 8); -+ reg16_write(client, 0x3803, priv->rect.top & 0xff); -+ /* vert crop end */ -+ reg16_write(client, 0x3806, (priv->rect.top + priv->rect.height + 1) >> 8); -+ reg16_write(client, 0x3807, (priv->rect.top + priv->rect.height + 1) & 0xff); -+#endif -+ /* enable clocks */ -+ reg16_write(client, 0x301b, 0xf0); -+ reg16_write(client, 0x301c, 0xf0); -+ reg16_write(client, 0x301a, 0xf0); -+ reg16_write(client, 0x302e, 0x01); ++ client->addr = priv->des_addr; /* MAX9286-CAMx I2C */ ++ reg8_write(client, 0x34, 0x22 | MAXIM_I2C_I2C_SPEED); /* disable artificial ACK, I2C speed set */ ++ usleep_range(2000, 2500); /* wait 2ms */ + -+ return 0; -+}; ++ /* I2C translator setup */ ++ client->addr = 0x40; /* MAX9271-CAMx I2C */ ++// reg8_write(client, 0x09, maxim_map[2][idx] << 1); /* SENSOR I2C translated - must be set by sensor driver */ ++// reg8_write(client, 0x0A, 0x30 << 1); /* SENSOR I2C native - must be set by sensor driver */ ++ reg8_write(client, 0x0B, BROADCAST << 1); /* broadcast I2C */ ++ reg8_write(client, 0x0C, priv->max9271_addr_map[idx] << 1); /* MAX9271-CAMx I2C new */ ++ /* I2C addresse change */ ++ reg8_write(client, 0x01, priv->des_addr << 1); /* MAX9286 I2C */ ++ reg8_write(client, 0x00, priv->max9271_addr_map[idx] << 1); /* MAX9271-CAM0 I2C new */ ++ usleep_range(2000, 2500); /* wait 2ms */ ++ /* put MAX9271 in configuration link state */ ++ client->addr = priv->max9271_addr_map[idx]; /* MAX9271-CAMx I2C new */ ++ reg8_write(client, 0x04, 0x43); /* enable reverse_control/conf_link */ ++ usleep_range(2000, 2500); /* wait 2ms */ ++#ifdef MAXIM_DUMP ++ client->addr = priv->des_addr; /* MAX9286-CAMx I2C */ ++ maxim_max927x_dump_regs(client); ++ client->addr = priv->max9271_addr_map[idx]; /* MAX9271-CAMx I2C new */ ++ maxim_max927x_dump_regs(client); ++#endif ++} + -+static int ov10635_get_fmt(struct v4l2_subdev *sd, -+ struct v4l2_subdev_pad_config *cfg, -+ struct v4l2_subdev_format *format) ++static int max9286_initialize(struct i2c_client *client) +{ -+ struct v4l2_mbus_framefmt *mf = &format->format; -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ struct ov10635_priv *priv = to_ov10635(client); ++ struct max9286_priv *priv = i2c_get_clientdata(client); ++ int idx, ret; + -+ if (format->pad) -+ return -EINVAL; ++ dev_info(&client->dev, "LINKs=%d, LANES=%d, FSYNC mode=%s, FSYNC period=%d, PCLK edge=%s\n", ++ priv->links, priv->lanes, priv->fsync_mode, priv->fsync_period, ++ priv->pclk_rising_edge ? "rising" : "falling"); + -+ mf->width = priv->rect.width; -+ mf->height = priv->rect.height; -+ mf->code = MEDIA_BUS_FMT_YUYV8_2X8; -+ mf->colorspace = V4L2_COLORSPACE_SMPTE170M; -+ mf->field = V4L2_FIELD_NONE; ++ if (priv->des_quirk_addr) ++ max9286_preinit(client, priv->des_quirk_addr); + -+ return 0; -+} ++ max9286_preinit(client, priv->des_addr); ++ max9286_initial_setup(client); + -+static int ov10635_set_fmt(struct v4l2_subdev *sd, -+ struct v4l2_subdev_pad_config *cfg, -+ struct v4l2_subdev_format *format) -+{ -+ struct v4l2_mbus_framefmt *mf = &format->format; ++ for (idx = 0; idx < priv->links; idx++) { ++ if (!IS_ERR(priv->poc_supply[idx])) { ++ if (regulator_enable(priv->poc_supply[idx])) ++ dev_err(&client->dev, "fail to enable POC%d regulator\n", idx); ++ mdelay(priv->poc_delay); ++ } + -+ mf->code = MEDIA_BUS_FMT_YUYV8_2X8; -+ mf->colorspace = V4L2_COLORSPACE_SMPTE170M; -+ mf->field = V4L2_FIELD_NONE; ++ ret = max9286_reverse_channel_setup(client, idx); ++ if (ret) ++ continue; ++ max9286_gmsl_link_setup(client, idx); ++ } + -+ if (format->which == V4L2_SUBDEV_FORMAT_TRY) -+ cfg->try_fmt = *mf; ++ max9286_postinit(client, priv->des_addr); ++ ++ client->addr = priv->des_addr; + + return 0; +} + -+static int ov10635_enum_mbus_code(struct v4l2_subdev *sd, -+ struct v4l2_subdev_pad_config *cfg, -+ struct v4l2_subdev_mbus_code_enum *code) ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int max9286_g_register(struct v4l2_subdev *sd, ++ struct v4l2_dbg_register *reg) +{ -+ if (code->pad || code->index > 0) -+ return -EINVAL; ++ struct max9286_priv *priv = v4l2_get_subdevdata(sd); ++ struct i2c_client *client = priv->client; ++ int ret; ++ u8 val = 0; + -+ code->code = MEDIA_BUS_FMT_YUYV8_2X8; ++ ret = reg8_read(client, (u8)reg->reg, &val); ++ if (ret < 0) ++ return ret; ++ ++ reg->val = val; ++ reg->size = sizeof(u8); + + return 0; +} + -+static int ov10635_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) ++static int max9286_s_register(struct v4l2_subdev *sd, ++ const struct v4l2_dbg_register *reg) +{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ struct ov10635_priv *priv = to_ov10635(client); ++ struct max9286_priv *priv = v4l2_get_subdevdata(sd); ++ struct i2c_client *client = priv->client; + -+ memcpy(edid->edid, priv->id, 6); ++ return reg8_write(client, (u8)reg->reg, (u8)reg->val); ++} ++#endif + -+ edid->edid[6] = 0xff; -+ edid->edid[7] = client->addr; -+ edid->edid[8] = OV10635_VERSION_REG >> 8; -+ edid->edid[9] = OV10635_VERSION_REG & 0xff; ++static int max9286_s_power(struct v4l2_subdev *sd, int on) ++{ ++ struct max9286_priv *priv = v4l2_get_subdevdata(sd); ++ struct i2c_client *client = priv->client; ++ ++ if (on) { ++ if (atomic_inc_return(&priv->use_count) == 1) ++ reg8_write(client, 0x69, priv->links_mask ^ 0x0f); /* unmask CSI forwarding from detected links */ ++ } else { ++ if (atomic_dec_return(&priv->use_count) == 0) ++ reg8_write(client, 0x69, 0x0f); /* mask CSI forwarding from all links */ ++ } + + return 0; +} + -+static int ov10635_set_selection(struct v4l2_subdev *sd, -+ struct v4l2_subdev_pad_config *cfg, -+ struct v4l2_subdev_selection *sel) ++static int max9286_registered_async(struct v4l2_subdev *sd) +{ -+ struct v4l2_rect *rect = &sel->r; -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ struct ov10635_priv *priv = to_ov10635(client); -+ int subsampling = 0; -+ -+ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || -+ sel->target != V4L2_SEL_TGT_CROP) -+ return -EINVAL; ++ struct max9286_priv *priv = v4l2_get_subdevdata(sd); ++ struct i2c_client *client = priv->client; ++ int idx, tmp_addr; + -+ rect->left = ALIGN(rect->left, 2); -+ rect->top = ALIGN(rect->top, 2); -+ rect->width = ALIGN(rect->width, 2); -+ rect->height = ALIGN(rect->height, 2); ++ /* switch to GMSL serial_link for streaming video */ ++ tmp_addr = client->addr; ++ idx = sd->grp_id; + -+ if ((rect->left + rect->width > OV10635_MAX_WIDTH) || -+ (rect->top + rect->height > OV10635_MAX_HEIGHT)) -+ *rect = priv->rect; ++ client->addr = priv->des_addr; /* MAX9286 I2C */ ++ reg8_write(client, 0x0a, 0x11 << idx); /* enable reverse/forward control for CAMx */ + -+ if (rect->width == OV10635_MAX_WIDTH / 2 && -+ rect->height == OV10635_MAX_HEIGHT / 2) -+ subsampling = 1; ++ client->addr = priv->max9271_addr_map[idx]; /* MAX9271-CAMx */ ++ reg8_write(client, 0x04, conf_link ? 0x43 : 0x83); /* enable serial_link */ ++ usleep_range(2000, 2500); /* wait 2ms after changing reverse_control */ + -+ priv->rect.left = rect->left; -+ priv->rect.top = rect->top; -+ priv->rect.width = rect->width; -+ priv->rect.height = rect->height; ++ client->addr = priv->des_addr; /* MAX9286 I2C */ ++ reg8_write(client, 0x0a, (priv->links_mask << 4) | priv->links_mask); /* enable reverse/forward control for all CAMs */ + -+ /* change window only for subsampling, crop is done by VIN */ -+ if (subsampling != priv->subsampling) { -+ ov10635_set_window(sd, subsampling); -+ priv->subsampling = subsampling; -+ } ++ client->addr = tmp_addr; + + return 0; +} + -+static int ov10635_get_selection(struct v4l2_subdev *sd, -+ struct v4l2_subdev_pad_config *cfg, -+ struct v4l2_subdev_selection *sel) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ struct ov10635_priv *priv = to_ov10635(client); -+ -+ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) -+ return -EINVAL; ++static struct v4l2_subdev_core_ops max9286_subdev_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = max9286_g_register, ++ .s_register = max9286_s_register, ++#endif ++ .s_power = max9286_s_power, ++ .registered_async = max9286_registered_async, ++}; + -+ switch (sel->target) { -+ case V4L2_SEL_TGT_CROP_BOUNDS: -+ sel->r.left = 0; -+ sel->r.top = 0; -+ sel->r.width = OV10635_MAX_WIDTH; -+ sel->r.height = OV10635_MAX_HEIGHT; -+ return 0; -+ case V4L2_SEL_TGT_CROP_DEFAULT: -+ sel->r.left = 0; -+ sel->r.top = 0; -+ sel->r.width = OV10635_MAX_WIDTH; -+ sel->r.height = OV10635_MAX_HEIGHT; -+ return 0; -+ case V4L2_SEL_TGT_CROP: -+ sel->r = priv->rect; -+ return 0; -+ default: -+ return -EINVAL; -+ } -+} ++static struct v4l2_subdev_ops max9286_subdev_ops = { ++ .core = &max9286_subdev_core_ops, ++}; + -+static int ov10635_g_mbus_config(struct v4l2_subdev *sd, -+ struct v4l2_mbus_config *cfg) ++static int max9286_parse_dt(struct i2c_client *client) +{ -+ cfg->flags = V4L2_MBUS_CSI2_1_LANE | V4L2_MBUS_CSI2_CHANNEL_0 | -+ V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; -+ cfg->type = V4L2_MBUS_CSI2; ++ struct max9286_priv *priv = i2c_get_clientdata(client); ++ struct device_node *np = client->dev.of_node; ++ struct device_node *endpoint = NULL; ++ struct property *prop; ++ int err, pwen, i; ++ int sensor_delay, gpio0 = 1, gpio1 = 1; + -+ return 0; -+} ++ u8 val = 0; + -+static int ov10635_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ struct ov10635_priv *priv = to_ov10635(client); -+ struct v4l2_captureparm *cp = &parms->parm.capture; ++ if (of_property_read_u32(np, "maxim,links", &priv->links)) ++ priv->links = 4; + -+ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) -+ return -EINVAL; ++ if (of_property_read_u32(np, "maxim,lanes", &priv->lanes)) ++ priv->lanes = 4; + -+ memset(cp, 0, sizeof(struct v4l2_captureparm)); -+ cp->capability = V4L2_CAP_TIMEPERFRAME; -+ cp->timeperframe.numerator = 1; -+ cp->timeperframe.denominator = priv->fps_denominator; ++ pwen = of_get_gpio(np, 0); ++ if (pwen > 0) { ++ err = gpio_request_one(pwen, GPIOF_OUT_INIT_HIGH, dev_name(&client->dev)); ++ if (err) ++ dev_err(&client->dev, "cannot request PWEN gpio %d: %d\n", pwen, err); ++ } + -+ return 0; -+} ++ mdelay(250); + -+static int ov10635_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ struct ov10635_priv *priv = to_ov10635(client); -+ struct v4l2_captureparm *cp = &parms->parm.capture; -+ int ret = 0; ++ reg8_read(client, 0x1e, &val); /* read max9286 ID */ ++ if (val != MAX9286_ID) { ++ prop = of_find_property(np, "reg", NULL); ++ if (prop) ++ of_remove_property(np, prop); ++ return -ENODEV; ++ } + -+ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) -+ return -EINVAL; -+ if (cp->extendedmode != 0) -+ return -EINVAL; ++ if (!of_property_read_u32(np, "maxim,gpio0", &gpio0) || ++ !of_property_read_u32(np, "maxim,gpio1", &gpio1)) ++ reg8_write(client, 0x0f, 0x08 | (gpio1 << 1) | gpio0); + -+ if (priv->fps_denominator != cp->timeperframe.denominator) { -+ switch (cp->timeperframe.denominator) { -+ case 5: -+ ret = ov10635_set_regs(client, ov10635_regs_5fps, -+ ARRAY_SIZE(ov10635_regs_5fps)); -+ break; -+ case 10: -+ ret = ov10635_set_regs(client, ov10635_regs_10fps, -+ ARRAY_SIZE(ov10635_regs_10fps)); -+ break; -+ case 15: -+ ret = ov10635_set_regs(client, ov10635_regs_15fps, -+ ARRAY_SIZE(ov10635_regs_15fps)); -+ break; -+ case 30: -+ ret = ov10635_set_regs(client, ov10635_regs_30fps, -+ ARRAY_SIZE(ov10635_regs_30fps)); -+ break; -+ default: -+ ret = -EINVAL; -+ goto out; -+ } ++ if (of_property_read_u32(np, "maxim,resetb-gpio", &priv->gpio_resetb)) { ++ priv->gpio_resetb = -1; ++ } else { ++ if (of_property_read_bool(np, "maxim,resetb-active-high")) ++ priv->active_low_resetb = 0; ++ else ++ priv->active_low_resetb = 1; ++ } + -+ priv->fps_denominator = cp->timeperframe.denominator; ++ if (!of_property_read_u32(np, "maxim,sensor_delay", &sensor_delay)) ++ mdelay(sensor_delay); ++ if (of_property_read_string(np, "maxim,fsync-mode", &priv->fsync_mode)) ++ priv->fsync_mode = fsync_mode_default; ++ if (of_property_read_u32(np, "maxim,fsync-period", &priv->fsync_period)) ++ priv->fsync_period = 3200000; /* 96MHz/30fps */ ++ priv->pclk_rising_edge = true; ++ if (of_property_read_bool(np, "maxim,pclk-falling-edge")) ++ priv->pclk_rising_edge = false; ++ if (of_property_read_u32(np, "maxim,timeout", &priv->timeout)) ++ priv->timeout = 100; ++ if (of_property_read_u32(np, "maxim,i2c-quirk", &priv->des_quirk_addr)) ++ priv->des_quirk_addr = 0; ++ if (of_property_read_u32(np, "maxim,him", &priv->him)) ++ priv->him = 0; ++ if (of_property_read_u32(np, "maxim,hsync", &priv->hsync)) ++ priv->hsync = 0; ++ if (of_property_read_u32(np, "maxim,vsync", &priv->vsync)) ++ priv->vsync = 1; ++ if (of_property_read_u32(np, "maxim,poc-delay", &priv->poc_delay)) ++ priv->poc_delay = 50; ++ ++ /* module params override dts */ ++ if (him) ++ priv->him = him; ++ if (fsync_period) { ++ priv->fsync_period = fsync_period; ++ priv->fsync_mode = fsync_mode_default; + } ++ if (hsync) ++ priv->hsync = hsync; ++ if (!vsync) ++ priv->vsync = vsync; ++ if (gpio_resetb) ++ priv->gpio_resetb = gpio_resetb; ++ if (active_low_resetb) ++ priv->active_low_resetb = active_low_resetb; ++ if (poc_delay) ++ priv->poc_delay = poc_delay; + -+out: -+ return ret; -+} ++ for (i = 0; i < priv->links; i++) { ++ endpoint = of_graph_get_next_endpoint(np, endpoint); ++ if (!endpoint) ++ break; + -+#ifdef CONFIG_VIDEO_ADV_DEBUG -+static int ov10635_g_register(struct v4l2_subdev *sd, -+ struct v4l2_dbg_register *reg) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ int ret; -+ u8 val = 0; ++ of_node_put(endpoint); + -+ ret = reg16_read(client, (u16)reg->reg, &val); -+ if (ret < 0) -+ return ret; ++ if (of_property_read_u32(endpoint, "max9271-addr", &priv->max9271_addr_map[i])) { ++ dev_err(&client->dev, "max9271-addr not set\n"); ++ return -EINVAL; ++ } + -+ reg->val = val; -+ reg->size = sizeof(u16); ++ priv->sd_of_node[i] = endpoint; ++ } + + return 0; +} + -+static int ov10635_s_register(struct v4l2_subdev *sd, -+ const struct v4l2_dbg_register *reg) ++static void max9286_setup_remote_endpoint(struct i2c_client *client) +{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct max9286_priv *priv = i2c_get_clientdata(client); ++ struct device_node *np = client->dev.of_node; ++ struct device_node *endpoint = NULL, *rendpoint = NULL; ++ int i; ++ struct property *csi_rate_prop, *dvp_order_prop; + -+ return reg16_write(client, (u16)reg->reg, (u8)reg->val); -+} -+#endif ++ for (i = 0; ; i++) { ++ endpoint = of_graph_get_next_endpoint(np, endpoint); ++ if (!endpoint) ++ break; + -+static struct v4l2_subdev_core_ops ov10635_core_ops = { -+#ifdef CONFIG_VIDEO_ADV_DEBUG -+ .g_register = ov10635_g_register, -+ .s_register = ov10635_s_register, -+#endif -+}; ++ of_node_put(endpoint); + -+static int ov10635_s_ctrl(struct v4l2_ctrl *ctrl) -+{ -+ struct v4l2_subdev *sd = to_sd(ctrl); -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ struct ov10635_priv *priv = to_ov10635(client); -+ int ret = -EINVAL; -+ u8 val = 0; ++ rendpoint = of_parse_phandle(endpoint, "remote-endpoint", 0); ++ if (!rendpoint) ++ continue; + -+ if (!priv->init_complete) -+ return 0; ++ csi_rate_prop = of_find_property(endpoint, "csi-rate", NULL); ++ if (csi_rate_prop) { ++ /* CSI2_RATE = PCLK*sizeof(YUV8)*links/lanes */ ++ priv->csi_rate = cpu_to_be32(100 * 8 * hweight8(priv->links_mask) / priv->lanes); ++ csi_rate_prop->value = &priv->csi_rate; ++ of_update_property(rendpoint, csi_rate_prop); ++ } + -+ switch (ctrl->id) { -+ case V4L2_CID_BRIGHTNESS: -+ /* AEC/AGC target */ -+ ret = reg16_write(client, 0xc46a, ctrl->val); -+ break; -+ case V4L2_CID_CONTRAST: -+ udelay(100); -+ ret = ov10635_set_regs(client, &ov10635_regs_contrast[ctrl->val][0], 18); -+ break; -+ case V4L2_CID_SATURATION: -+ ret = reg16_write(client, 0xc316, ctrl->val); -+ break; -+ case V4L2_CID_HUE: -+ /* CMX ? */ -+ ret = 0; -+ break; -+ case V4L2_CID_GAMMA: -+ ret = reg16_write(client, 0xc4be, ctrl->val >> 8); -+ ret |= reg16_write(client, 0xc4bf, ctrl->val & 0xff); -+ break; -+ case V4L2_CID_AUTOGAIN: -+ /* automatic gain/exposure */ -+ ret = reg16_write(client, 0x56d0, !ctrl->val); -+ break; -+ case V4L2_CID_GAIN: -+ /* manual gain */ -+ ret = reg16_write(client, 0x3504, 0); -+ ret |= reg16_write(client, 0x56d1, ctrl->val >> 8); -+ ret |= reg16_write(client, 0x56d2, ctrl->val & 0xff); -+ ret |= reg16_write(client, 0x3504, 1); /* validate gain */ -+ break; -+ case V4L2_CID_EXPOSURE: -+ /* manual exposure */ -+ ret = reg16_write(client, 0x3504, 0); -+ ret |= reg16_write(client, 0x56d5, ctrl->val >> 8); -+ ret |= reg16_write(client, 0x56d6, ctrl->val & 0xff); -+ ret |= reg16_write(client, 0x3504, 1); /* validate exposure */ -+ break; -+ case V4L2_CID_HFLIP: -+ ret = reg16_read(client, 0x381d, &val); -+ if (ret < 0) -+ goto out; -+ if (ctrl->val) -+ val |= 0x3; -+ else -+ val &= ~0x3; -+ ret = reg16_write(client, 0x381d, val); -+ break; -+ case V4L2_CID_VFLIP: -+ ret = reg16_read(client, 0x381c, &val); -+ if (ctrl->val) -+ val |= 0xc0; -+ else -+ val &= ~0xc0; -+ ret = reg16_write(client, 0x381c, val); -+ break; -+ case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: -+ ret = 0; -+ break; ++ dvp_order_prop = of_find_property(endpoint, "dvp-order", NULL); ++ if (dvp_order_prop) ++ of_update_property(rendpoint, dvp_order_prop); + } -+ -+out: -+ return ret; +} + -+static const struct v4l2_ctrl_ops ov10635_ctrl_ops = { -+ .s_ctrl = ov10635_s_ctrl, -+}; -+ -+static struct v4l2_subdev_video_ops ov10635_video_ops = { -+ .s_stream = ov10635_s_stream, -+ .g_mbus_config = ov10635_g_mbus_config, -+ .g_parm = ov10635_g_parm, -+ .s_parm = ov10635_s_parm, -+}; -+ -+static const struct v4l2_subdev_pad_ops ov10635_subdev_pad_ops = { -+ .get_edid = ov10635_get_edid, -+ .enum_mbus_code = ov10635_enum_mbus_code, -+ .get_selection = ov10635_get_selection, -+ .set_selection = ov10635_set_selection, -+ .get_fmt = ov10635_get_fmt, -+ .set_fmt = ov10635_set_fmt, -+}; -+ -+static struct v4l2_subdev_ops ov10635_subdev_ops = { -+ .core = &ov10635_core_ops, -+ .video = &ov10635_video_ops, -+ .pad = &ov10635_subdev_pad_ops, -+}; -+ -+static void ov10635_otp_id_read(struct i2c_client *client) ++static int max9286_probe(struct i2c_client *client, ++ const struct i2c_device_id *did) +{ -+ struct ov10635_priv *priv = to_ov10635(client); -+ int i; -+ -+ /* read camera id from OTP memory */ -+ reg16_write(client, 0x3d10, 1); ++ struct max9286_priv *priv; ++ int err, i; ++ char supply_name[10]; + -+ usleep_range(15000, 16000); /* wait 15ms */ ++ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; + -+ for (i = 0; i < 6; i++) -+ reg16_read(client, 0x3d00 + i, &priv->id[i]); -+} ++ i2c_set_clientdata(client, priv); ++ priv->des_addr = client->addr; ++ priv->client = client; ++ atomic_set(&priv->use_count, 0); ++ priv->csi2_outord = 0xff; + -+static ssize_t ov10635_otp_id_show(struct device *dev, -+ struct device_attribute *attr, char *buf) -+{ -+ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev)); -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ struct ov10635_priv *priv = to_ov10635(client); ++ err = max9286_parse_dt(client); ++ if (err) ++ goto out; + -+ return snprintf(buf, 32, "%02x:%02x:%02x:%02x:%02x:%02x\n", -+ priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); -+} ++ for (i = 0; i < 4; i++) { ++ sprintf(supply_name, "POC%d", i); ++ priv->poc_supply[i] = devm_regulator_get_optional(&client->dev, supply_name); ++ } + -+static DEVICE_ATTR(otp_id_ov10635, S_IRUGO, ov10635_otp_id_show, NULL); ++ err = max9286_initialize(client); ++ if (err < 0) ++ goto out; + -+static int ov10635_initialize(struct i2c_client *client) -+{ -+ struct ov10635_priv *priv = to_ov10635(client); -+ u8 pid = 0, ver = 0; -+ int ret = 0; ++ max9286_setup_remote_endpoint(client); + -+ ov10635_s_port(client, 1); ++ for (i = 0; i < 4; i++) { ++ v4l2_subdev_init(&priv->sd[i], &max9286_subdev_ops); ++ priv->sd[i].owner = client->dev.driver->owner; ++ priv->sd[i].dev = &client->dev; ++ priv->sd[i].grp_id = i; ++ v4l2_set_subdevdata(&priv->sd[i], priv); ++ priv->sd[i].of_node = priv->sd_of_node[i]; + -+ /* check and show product ID and manufacturer ID */ -+ reg16_read(client, OV10635_PID, &pid); -+ reg16_read(client, OV10635_VER, &ver); ++ snprintf(priv->sd[i].name, V4L2_SUBDEV_NAME_SIZE, "%s.%d %d-%04x", ++ client->dev.driver->name, i, i2c_adapter_id(client->adapter), ++ client->addr); + -+ if (OV10635_VERSION(pid, ver) != OV10635_VERSION_REG) { -+ dev_dbg(&client->dev, "Product ID error %x:%x\n", pid, ver); -+ ret = -ENODEV; -+ goto out; ++ err = v4l2_async_register_subdev(&priv->sd[i]); ++ if (err < 0) ++ goto out; + } -+ -+ /* s/w reset sensor */ -+ reg16_write(client, 0x103, 0x1); -+ udelay(100); -+ /* Program wizard registers */ -+ ov10635_set_regs(client, ov10635_regs_wizard, ARRAY_SIZE(ov10635_regs_wizard)); -+ /* Set DVP bit swap */ -+ reg16_write(client, 0x4709, priv->dvp_order << 4); -+ /* Read OTP IDs */ -+ ov10635_otp_id_read(client); -+ -+ dev_info(&client->dev, "ov10635 Product ID %x Manufacturer ID %x OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n", -+ pid, ver, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); +out: -+ ov10635_s_port(client, 0); -+ -+ return ret; ++ return err; +} + -+static int ov10635_parse_dt(struct device_node *np, struct ov10635_priv *priv) ++static int max9286_remove(struct i2c_client *client) +{ -+ struct i2c_client *client = v4l2_get_subdevdata(&priv->sd); ++ struct max9286_priv *priv = i2c_get_clientdata(client); + int i; -+ struct device_node *endpoint = NULL, *rendpoint = NULL; -+ int tmp_addr = 0; -+ -+ for (i = 0; ; i++) { -+ endpoint = of_graph_get_next_endpoint(np, endpoint); -+ if (!endpoint) -+ break; + -+ of_node_put(endpoint); ++ for (i = 0; i < 4; i++) { ++ v4l2_async_unregister_subdev(&priv->sd[i]); ++ v4l2_device_unregister_subdev(&priv->sd[i]); ++ } + -+ of_property_read_u32(endpoint, "dvp-order", &priv->dvp_order); ++ return 0; ++} + -+ rendpoint = of_parse_phandle(endpoint, "remote-endpoint", 0); -+ if (!rendpoint) -+ continue; ++static const struct of_device_id max9286_dt_ids[] = { ++ { .compatible = "maxim,max9286" }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, max9286_dt_ids); + -+ if (!of_property_read_u32(rendpoint, "max9271-addr", &priv->max9271_addr) && -+ !of_property_read_u32(rendpoint->parent->parent, "reg", &priv->max9286_addr) && -+ !kstrtouint(strrchr(rendpoint->full_name, '@') + 1, 0, &priv->port)) -+ break; ++static const struct i2c_device_id max9286_id[] = { ++ { "max9286", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, max9286_id); + -+ if (!of_property_read_u32(rendpoint, "ti9x3-addr", &priv->ti9x3_addr) && -+ !of_property_match_string(rendpoint->parent->parent, "compatible", "ti,ti964-ti9x3") && -+ !of_property_read_u32(rendpoint->parent->parent, "reg", &priv->ti964_addr) && -+ !kstrtouint(strrchr(rendpoint->full_name, '@') + 1, 0, &priv->port)) -+ break; ++static struct i2c_driver max9286_i2c_driver = { ++ .driver = { ++ .name = "max9286", ++ .of_match_table = of_match_ptr(max9286_dt_ids), ++ }, ++ .probe = max9286_probe, ++ .remove = max9286_remove, ++ .id_table = max9286_id, ++}; + -+ if (!of_property_read_u32(rendpoint, "ti9x3-addr", &priv->ti9x3_addr) && -+ !of_property_match_string(rendpoint->parent->parent, "compatible", "ti,ti954-ti9x3") && -+ !of_property_read_u32(rendpoint->parent->parent, "reg", &priv->ti954_addr) && -+ !kstrtouint(strrchr(rendpoint->full_name, '@') + 1, 0, &priv->port)) -+ break; -+ } ++module_i2c_driver(max9286_i2c_driver); + -+ if (!priv->max9286_addr && !priv->ti964_addr && !priv->ti954_addr) { -+ dev_err(&client->dev, "deserializer does not present for OV10635\n"); -+ return -EINVAL; -+ } ++MODULE_DESCRIPTION("GMSL driver for MAX9286"); ++MODULE_AUTHOR("Vladimir Barinov"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/media/i2c/soc_camera/max9286.h b/drivers/media/i2c/soc_camera/max9286.h +new file mode 100644 +index 0000000..6c2a9e0 +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/max9286.h +@@ -0,0 +1,244 @@ ++/* ++ * MAXIM max9286-max9271 GMSL driver include file ++ * ++ * Copyright (C) 2015-2017 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ + -+ ov10635_s_port(client, 1); ++#ifndef _MAX9286_MAX9271_H ++#define _MAX9286_MAX9271_H + -+ /* setup I2C translator address */ -+ tmp_addr = client->addr; -+ if (priv->max9286_addr) { -+ client->addr = priv->max9271_addr; /* Serializer I2C address */ ++//#define DEBUG ++#ifdef DEBUG ++//#define WRITE_VERIFY ++#define MAXIM_DUMP ++#undef dev_dbg ++#define dev_dbg dev_info ++#endif + -+ reg8_write(client, 0x09, tmp_addr << 1); /* Sensor translated I2C address */ -+ reg8_write(client, 0x0A, OV10635_I2C_ADDR << 1); /* Sensor native I2C address */ -+ usleep_range(2000, 2500); /* wait 2ms */ -+ }; ++#define REG8_NUM_RETRIES 1 /* number of read/write retries */ ++#define REG16_NUM_RETRIES 10 /* number of read/write retries */ ++#define MAX9271_ID 0x9 ++#define MAX96705_ID 0x41 ++#define MAX9286_ID 0x40 ++#define BROADCAST 0x6f + -+ if (priv->ti964_addr) { -+ client->addr = priv->ti964_addr; /* Deserializer I2C address */ ++static inline int reg8_read(struct i2c_client *client, u8 reg, u8 *val) ++{ ++ int ret, retries; + -+ reg8_write(client, 0x4c, (priv->port << 4) | (1 << priv->port)); /* Select RX port number */ -+ usleep_range(2000, 2500); /* wait 2ms */ -+ reg8_write(client, 0x65, tmp_addr << 1); /* Sensor translated I2C address */ -+ reg8_write(client, 0x5d, OV10635_I2C_ADDR << 1); /* Sensor native I2C address */ ++ for (retries = REG8_NUM_RETRIES; retries; retries--) { ++ ret = i2c_smbus_read_byte_data(client, reg); ++ if (!(ret < 0)) ++ break; ++ } + -+ reg8_write(client, 0x6e, 0xa9); /* GPIO0 - resetb, GPIO1 - fsin */ ++ if (ret < 0) { ++ dev_dbg(&client->dev, ++ "read fail: chip 0x%x register 0x%x: %d\n", ++ client->addr, reg, ret); ++ } else { ++ *val = ret; + } + -+ if (priv->ti954_addr) { -+ client->addr = priv->ti954_addr; /* Deserializer I2C address */ ++ return ret < 0 ? ret : 0; ++} + -+ reg8_write(client, 0x4c, (priv->port << 4) | (1 << priv->port)); /* Select RX port number */ -+ usleep_range(2000, 2500); /* wait 2ms */ -+ reg8_write(client, 0x65, tmp_addr << 1); /* Sensor translated I2C address */ -+ reg8_write(client, 0x5d, OV10635_I2C_ADDR << 1); /* Sensor native I2C address */ ++static inline int reg8_write(struct i2c_client *client, u8 reg, u8 val) ++{ ++ int ret, retries; + -+ reg8_write(client, 0x6e, 0xa9); /* GPIO0 - resetb, GPIO1 - fsin */ ++ for (retries = REG8_NUM_RETRIES; retries; retries--) { ++ ret = i2c_smbus_write_byte_data(client, reg, val); ++ if (!(ret < 0)) ++ break; + } -+ client->addr = tmp_addr; + -+ udelay(100); ++ if (ret < 0) { ++ dev_dbg(&client->dev, ++ "write fail: chip 0x%x register 0x%x: %d\n", ++ client->addr, reg, ret); ++ } else { ++#ifdef WRITE_VERIFY ++ u8 val2; ++ reg8_read(client, reg, &val2); ++ if (val != val2) ++ dev_err(&client->dev, ++ "write verify mismatch: chip 0x%x reg=0x%x " ++ "0x%x->0x%x\n", client->addr, reg, val, val2); ++#endif ++ } + -+ return 0; ++ return ret < 0 ? ret : 0; +} + -+static int ov10635_probe(struct i2c_client *client, -+ const struct i2c_device_id *did) ++static inline int reg16_read(struct i2c_client *client, u16 reg, u8 *val) +{ -+ struct ov10635_priv *priv; -+ struct v4l2_ctrl *ctrl; -+ int ret; ++ int ret, retries; ++ u8 buf[2] = {reg >> 8, reg & 0xff}; + -+ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; ++ for (retries = REG16_NUM_RETRIES; retries; retries--) { ++ ret = i2c_master_send(client, buf, 2); ++ if (ret == 2) { ++ ret = i2c_master_recv(client, buf, 1); ++ if (ret == 1) ++ break; ++ } ++ } + -+ v4l2_i2c_subdev_init(&priv->sd, client, &ov10635_subdev_ops); -+ priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; -+ priv->rect.left = 0; -+ priv->rect.top = 0; -+ priv->rect.width = OV10635_MAX_WIDTH; -+ priv->rect.height = OV10635_MAX_HEIGHT; -+ priv->fps_denominator = 30; ++ if (ret < 0) { ++ dev_dbg(&client->dev, ++ "read fail: chip 0x%x register 0x%x: %d\n", ++ client->addr, reg, ret); ++ } else { ++ *val = buf[0]; ++ } + -+ v4l2_ctrl_handler_init(&priv->hdl, 4); -+ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops, -+ V4L2_CID_BRIGHTNESS, 0, 0xff, 1, 0x30); -+ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops, -+ V4L2_CID_CONTRAST, 0, 4, 1, 2); -+ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops, -+ V4L2_CID_SATURATION, 0, 0xff, 1, 0xff); -+ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops, -+ V4L2_CID_HUE, 0, 255, 1, 0); -+ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops, -+ V4L2_CID_GAMMA, 0, 0xffff, 1, 0x233); -+ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops, -+ V4L2_CID_AUTOGAIN, 0, 1, 1, 1); -+ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops, -+ V4L2_CID_GAIN, 0, 0x3ff, 1, 0x10); -+ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops, -+ V4L2_CID_EXPOSURE, 0, 0xffff, 1, 0x80); -+ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops, -+ V4L2_CID_HFLIP, 0, 1, 1, 0); -+ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops, -+ V4L2_CID_VFLIP, 0, 1, 1, 0); -+ ctrl = v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops, -+ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 9); -+ if (ctrl) -+ ctrl->flags &= ~V4L2_CTRL_FLAG_READ_ONLY; -+ priv->sd.ctrl_handler = &priv->hdl; ++ return ret < 0 ? ret : 0; ++} + -+ ret = priv->hdl.error; -+ if (ret) -+ goto cleanup; ++static inline int reg16_write(struct i2c_client *client, u16 reg, u8 val) ++{ ++ int ret, retries; ++ u8 buf[3] = {reg >> 8, reg & 0xff, val}; + -+ v4l2_ctrl_handler_setup(&priv->hdl); ++ for (retries = REG16_NUM_RETRIES; retries; retries--) { ++ ret = i2c_master_send(client, buf, 3); ++ if (ret == 3) ++ break; ++ } + -+ priv->pad.flags = MEDIA_PAD_FL_SOURCE; -+ priv->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR; -+ ret = media_entity_pads_init(&priv->sd.entity, 1, &priv->pad); -+ if (ret < 0) -+ goto cleanup; ++ if (ret < 0) { ++ dev_dbg(&client->dev, ++ "write fail: chip 0x%x register 0x%x: %d\n", ++ client->addr, reg, ret); ++ } else { ++#ifdef WRITE_VERIFY ++ u8 val2; ++ reg16_read(client, reg, &val2); ++ if (val != val2) ++ dev_err(&client->dev, ++ "write verify mismatch: chip 0x%x reg=0x%x " ++ "0x%x->0x%x\n", client->addr, reg, val, val2); ++#endif ++ } + -+ ret = ov10635_parse_dt(client->dev.of_node, priv); -+ if (ret) -+ goto cleanup; ++ return ret < 0 ? ret : 0; ++} + -+ ret = ov10635_initialize(client); -+ if (ret < 0) -+ goto cleanup; + -+ ret = v4l2_async_register_subdev(&priv->sd); -+ if (ret) -+ goto cleanup; ++static inline int reg16_read16(struct i2c_client *client, u16 reg, u16 *val) ++{ ++ int ret, retries; ++ u8 buf[2] = {reg >> 8, reg & 0xff}; + -+ if (device_create_file(&client->dev, &dev_attr_otp_id_ov10635) != 0) { -+ dev_err(&client->dev, "sysfs otp_id entry creation failed\n"); -+ goto cleanup; ++ for (retries = REG8_NUM_RETRIES; retries; retries--) { ++ ret = i2c_master_send(client, buf, 2); ++ if (ret == 2) { ++ ret = i2c_master_recv(client, buf, 2); ++ if (ret == 2) ++ break; ++ } + } + -+ priv->init_complete = 1; -+ -+ return 0; ++ if (ret < 0) { ++ dev_err(&client->dev, ++ "read fail: chip 0x%x register 0x%x: %d\n", ++ client->addr, reg, ret); ++ } else { ++ *val = ((u16)buf[0] << 8) | buf[1]; ++ } + -+cleanup: -+ media_entity_cleanup(&priv->sd.entity); -+ v4l2_ctrl_handler_free(&priv->hdl); -+ v4l2_device_unregister_subdev(&priv->sd); -+#ifdef CONFIG_SOC_CAMERA_OV10635 -+ v4l_err(client, "failed to probe @ 0x%02x (%s)\n", -+ client->addr, client->adapter->name); -+#endif -+ return ret; ++ return ret < 0 ? ret : 0; +} + -+static int ov10635_remove(struct i2c_client *client) ++static inline int reg16_write16(struct i2c_client *client, u16 reg, u16 val) +{ -+ struct ov10635_priv *priv = i2c_get_clientdata(client); ++ int ret, retries; ++ u8 buf[4] = {reg >> 8, reg & 0xff, val >> 8, val & 0xff}; + -+ device_remove_file(&client->dev, &dev_attr_otp_id_ov10635); -+ v4l2_async_unregister_subdev(&priv->sd); -+ media_entity_cleanup(&priv->sd.entity); -+ v4l2_ctrl_handler_free(&priv->hdl); -+ v4l2_device_unregister_subdev(&priv->sd); ++ for (retries = REG8_NUM_RETRIES; retries; retries--) { ++ ret = i2c_master_send(client, buf, 4); ++ if (ret == 4) ++ break; ++ } + -+ return 0; ++ if (ret < 0) { ++ dev_err(&client->dev, ++ "write fail: chip 0x%x register 0x%x: %d\n", ++ client->addr, reg, ret); ++ } ++ ++ return ret < 0 ? ret : 0; +} + -+#ifdef CONFIG_SOC_CAMERA_OV10635 -+static const struct i2c_device_id ov10635_id[] = { -+ { "ov10635", 0 }, -+ { } -+}; -+MODULE_DEVICE_TABLE(i2c, ov10635_id); + -+static const struct of_device_id ov10635_of_ids[] = { -+ { .compatible = "ovti,ov10635", }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, ov10635_of_ids); ++#ifdef MAXIM_DUMP ++static void maxim_ovsensor_dump_regs(struct i2c_client *client) ++{ ++ int ret, i; ++ u8 val = 0; ++ u16 regs[] = {0x300a, 0x300b, 0x300c}; + -+static struct i2c_driver ov10635_i2c_driver = { -+ .driver = { -+ .name = "ov10635", -+ .of_match_table = ov10635_of_ids, -+ }, -+ .probe = ov10635_probe, -+ .remove = ov10635_remove, -+ .id_table = ov10635_id, -+}; ++ dev_dbg(&client->dev, "dump regs 0x%x\n", client->addr); + -+module_i2c_driver(ov10635_i2c_driver); ++ for (i = 0; i < sizeof(regs) / 2; i++) { ++ ret = reg16_read(client, regs[i], &val); ++ if (ret < 0) ++ dev_err(&client->dev, ++ "read fail: chip 0x%x register 0x%02x: %d\n", ++ client->addr, regs[i], ret); ++ printk("0x%02x -> 0x%x\n", regs[i], val); ++ } ++} + -+MODULE_DESCRIPTION("SoC Camera driver for OV10635"); -+MODULE_AUTHOR("Vladimir Barinov"); -+MODULE_LICENSE("GPL"); -+#endif -diff --git a/drivers/media/i2c/soc_camera/ov10635.h b/drivers/media/i2c/soc_camera/ov10635.h ++static void maxim_ov10635_dump_format_regs(struct i2c_client *client) ++{ ++ int ret, i; ++ u8 val; ++ u16 regs[] = {0x3003, 0x3004, 0x4300, ++ 0x4605, 0x3621, 0x3702, 0x3703, 0x3704, ++ 0x3802, 0x3803, 0x3806, 0x3807, 0x3808, 0x3809, 0x380a, ++ 0x380b, 0x380c, 0x380d, 0x380e, 0x380f, ++ 0x4606, 0x4607, 0x460a, 0x460b, ++ 0xc488, 0xc489, 0xc48a, 0xc48b, ++ 0xc4cc, 0xc4cd, 0xc4ce, 0xc4cf, 0xc512, 0xc513, ++ 0xc518, 0xc519, 0xc51a, 0xc51b, ++ }; ++ ++ dev_dbg(&client->dev, "dump regs 0x%x\n", client->addr); ++ ++ for (i = 0; i < sizeof(regs) / 2; i++) { ++ ret = reg16_read(client, regs[i], &val); ++ if (ret < 0) ++ dev_err(&client->dev, ++ "read fail: chip 0x%x register 0x%02x: %d\n", ++ client->addr, regs[i], ret); ++ printk("0x%02x -> 0x%x\n", regs[i], val); ++ } ++} ++ ++static void maxim_max927x_dump_regs(struct i2c_client *client) ++{ ++ int ret; ++ u8 reg; ++ ++ dev_dbg(&client->dev, "dump regs 0x%x\n", client->addr); ++ ++ for (reg = 0; reg < 0x20; reg++) { ++ ret = i2c_smbus_read_byte_data(client, reg); ++ if (ret < 0) ++ dev_err(&client->dev, ++ "read fail: chip 0x%x register 0x%x: %d\n", ++ client->addr, reg, ret); ++ printk("0x%02x ", ret); ++ if (((reg + 1) % 0x10) == 0) ++ printk("\n"); ++ } ++} ++#endif /* MAXIM_DUMP */ ++#endif /* _MAX9286_MAX9271_H */ +diff --git a/drivers/media/i2c/soc_camera/ov10635.c b/drivers/media/i2c/soc_camera/ov10635.c new file mode 100644 -index 0000000..a0e510d +index 0000000..8c06e59 --- /dev/null -+++ b/drivers/media/i2c/soc_camera/ov10635.h -@@ -0,0 +1,1139 @@ ++++ b/drivers/media/i2c/soc_camera/ov10635.c +@@ -0,0 +1,759 @@ +/* -+ * OmniVision ov10635 sensor camera wizard 1280x800@30/UYVY/BT601/8bit ++ * OmniVision ov10635 sensor camera driver + * + * Copyright (C) 2015-2017 Cogent Embedded, Inc. + * @@ -3301,1531 +3098,144 @@ index 0000000..a0e510d + * option) any later version. + */ + -+//#define OV10635_DISPLAY_PATTERN ++#include ++#include ++#include ++#include ++#include + -+#define OV10635_SENSOR_WIDTH 1312 -+#define OV10635_SENSOR_HEIGHT 814 ++#include ++#include ++#include ++#include + -+#define OV10635_MAX_WIDTH 1280 -+#define OV10635_MAX_HEIGHT 800 ++#include "max9286.h" ++#include "ov10635.h" + -+//#define OV10635_PCLK_96MHZ -+#define OV10635_PCLK_88MHZ ++#define OV10635_I2C_ADDR 0x30 + -+#if defined(OV10635_PCLK_96MHZ) -+/* VTS=PCLK/FPS/HTS/2 (=96MHz/30/1600/2) */ -+ #define OV10635_HTS 1600 -+ #define OV10635_VTS 1000 /* fps=30 */ -+#elif defined(OV10635_PCLK_88MHZ) -+/* VTS=PCLK/FPS/HTS/2 (=88MHz/1572/30/2) */ -+ #define OV10635_HTS 1572 -+ #define OV10635_VTS 933 /* fps=29.9998 */ -+#else -+ #error PCLK not defined ++#define OV10635_PID 0x300a ++#define OV10635_VER 0x300b ++#define OV10635_VERSION_REG 0xa635 ++#define OV10635_VERSION(pid, ver) (((pid) << 8) | ((ver) & 0xff)) ++ ++struct ov10635_priv { ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct media_pad pad; ++ struct v4l2_rect rect; ++ int subsampling; ++ int fps_denominator; ++ int init_complete; ++ u8 id[6]; ++ int dvp_order; ++ /* serializers */ ++ int max9286_addr; ++ int max9271_addr; ++ int ti964_addr; ++ int ti954_addr; ++ int ti9x3_addr; ++ int port; ++ int gpio_resetb; ++ int gpio_fsin; ++}; ++ ++static inline struct ov10635_priv *to_ov10635(const struct i2c_client *client) ++{ ++ return container_of(i2c_get_clientdata(client), struct ov10635_priv, sd); ++} ++ ++static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) ++{ ++ return &container_of(ctrl->handler, struct ov10635_priv, hdl)->sd; ++} ++ ++static void ov10635_s_port(struct i2c_client *client, int fwd_en) ++{ ++ struct ov10635_priv *priv = to_ov10635(client); ++ int tmp_addr; ++ ++ if (priv->max9286_addr) { ++ tmp_addr = client->addr; ++ client->addr = priv->max9286_addr; /* Deserializer I2C address */ ++ reg8_write(client, 0x0a, fwd_en ? 0x11 << priv->port : 0); /* Enable/disable reverse/forward control for this port */ ++ usleep_range(5000, 5500); /* wait 5ms */ ++ client->addr = tmp_addr; ++ }; ++} ++ ++static int ov10635_set_regs(struct i2c_client *client, ++ const struct ov10635_reg *regs, int nr_regs) ++{ ++ int i; ++ ++ for (i = 0; i < nr_regs; i++) { ++ if (reg16_write(client, regs[i].reg, regs[i].val)) { ++ usleep_range(100, 150); /* wait 100ns */ ++ reg16_write(client, regs[i].reg, regs[i].val); ++ } ++ } ++ ++ return 0; ++} ++ ++static int ov10635_s_stream(struct v4l2_subdev *sd, int enable) ++{ ++ return 0; ++} ++ ++static int ov10635_set_window(struct v4l2_subdev *sd, int subsampling) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov10635_priv *priv = to_ov10635(client); ++ ++ /* disable clocks */ ++ reg16_write(client, 0x302e, 0x00); ++ reg16_write(client, 0x301b, 0xff); ++ reg16_write(client, 0x301c, 0xff); ++ reg16_write(client, 0x301a, 0xff); ++ ++ /* setup resolution */ ++ reg16_write(client, 0x3808, priv->rect.width >> 8); ++ reg16_write(client, 0x3809, priv->rect.width & 0xff); ++ reg16_write(client, 0x380a, priv->rect.height >> 8); ++ reg16_write(client, 0x380b, priv->rect.height & 0xff); ++ ++ /* enable/disable subsampling */ ++ reg16_write(client, 0x5005, subsampling ? 0x89 : 0x08); ++ reg16_write(client, 0x3007, subsampling ? 0x02 : 0x01); ++ reg16_write(client, 0x4004, subsampling ? 0x02 : 0x04); ++ ++#if 0 /* This is implemented in VIN via SOC_CAMERA layer, hence skip */ ++ /* horiz crop start */ ++ reg16_write(client, 0x3800, priv->rect.left >> 8); ++ reg16_write(client, 0x3801, priv->rect.left & 0xff); ++ /* horiz crop end */ ++ reg16_write(client, 0x3804, (priv->rect.left + priv->rect.width + 1) >> 8); ++ reg16_write(client, 0x3805, (priv->rect.left + priv->rect.width + 1) & 0xff); ++ /* vert crop start */ ++ reg16_write(client, 0x3802, priv->rect.top >> 8); ++ reg16_write(client, 0x3803, priv->rect.top & 0xff); ++ /* vert crop end */ ++ reg16_write(client, 0x3806, (priv->rect.top + priv->rect.height + 1) >> 8); ++ reg16_write(client, 0x3807, (priv->rect.top + priv->rect.height + 1) & 0xff); +#endif ++ /* enable clocks */ ++ reg16_write(client, 0x301b, 0xf0); ++ reg16_write(client, 0x301c, 0xf0); ++ reg16_write(client, 0x301a, 0xf0); ++ reg16_write(client, 0x302e, 0x01); + -+struct ov10635_reg { -+ u16 reg; -+ u8 val; ++ return 0; +}; + -+static const struct ov10635_reg ov10635_regs_wizard[] = { -+//{0x0103, 0x01}, -+{0x300C, 0x61}, -+{0x300C, 0x61}, -+{0x300C, 0x61}, -+{0x300C, 0x61}, -+{0x300C, 0x61}, -+{0x300C, 0x61}, -+{0x300C, 0x61}, -+{0x300C, 0x61}, -+{0x300C, 0x61}, -+{0x300C, 0x61}, -+{0x300C, 0x61}, -+{0x300C, 0x61}, -+{0x300C, 0x61}, -+{0x300C, 0x61}, -+{0x300C, 0x61}, -+{0x300C, 0x61}, -+{0x300C, 0x61}, -+{0x300C, 0x61}, -+{0x300C, 0x61}, -+{0x300C, 0x61}, -+{0x300C, 0x61}, -+{0x300C, 0x61}, -+{0x300C, 0x61}, -+{0x301B, 0xFF}, -+{0x301C, 0xFF}, -+{0x301A, 0xFF}, -+{0x3011, 0x42}, -+{0x6900, 0x0C}, -+{0x6901, 0x19}, -+{0x3503, 0x10}, -+{0x3025, 0x03}, -+#if defined(OV10635_PCLK_96MHZ) -+{0x3003, 0x20}, -+{0x3004, 0x21}, -+#elif defined(OV10635_PCLK_88MHZ) -+{0x3003, 0x16}, -+{0x3004, 0x30}, -+#endif -+{0x3005, 0x40}, -+{0x3006, 0x91}, -+{0x3600, 0x74}, -+{0x3601, 0x2B}, -+{0x3612, 0x00}, -+{0x3611, 0x67}, -+{0x3633, 0xCA}, -+{0x3602, 0xAF}, -+{0x3603, 0x04}, -+{0x3630, 0x28}, -+{0x3631, 0x16}, -+{0x3714, 0x10}, -+{0x371D, 0x01}, -+{0x4300, 0x3A}, -+{0x3007, 0x01}, -+{0x3024, 0x03}, -+{0x3020, 0x0A}, -+{0x3702, 0x0D}, -+{0x3703, 0x20}, -+{0x3704, 0x15}, -+{0x3709, 0xA8}, -+{0x370C, 0xC7}, -+{0x370D, 0x80}, -+{0x3712, 0x00}, -+{0x3713, 0x20}, -+{0x3715, 0x04}, -+{0x381D, 0x40}, -+{0x381C, 0x00}, -+{0x3822, 0x50}, -+{0x3824, 0x10}, -+{0x3815, 0x8C}, -+{0x3804, 0x05}, -+{0x3805, 0x1F}, -+{0x3800, 0x00}, -+{0x3801, 0x00}, -+{0x3806, 0x03}, -+{0x3807, 0x28}, -+{0x3802, 0x00}, -+{0x3803, 0x07}, -+{0x3808, 0x05}, -+{0x3809, 0x00}, -+{0x380A, 0x03}, -+{0x380B, 0x20}, -+{0x380C, OV10635_HTS >> 8}, -+{0x380D, OV10635_HTS & 0xff}, -+{0x380E, OV10635_VTS >> 8}, -+{0x380F, OV10635_VTS & 0xff}, -+{0x3813, 0x02}, -+{0x3811, 0x08}, -+{0x381F, 0x0C}, -+{0x3819, 0x04}, -+{0x3804, 0x01}, -+{0x3805, 0x00}, -+{0x3828, 0x03}, -+{0x3829, 0x10}, -+{0x382A, 0x10}, -+{0x3621, 0x63}, -+{0x5005, 0x08}, -+{0x56D5, 0x00}, -+{0x56D6, 0x80}, -+{0x56D7, 0x00}, -+{0x56D8, 0x00}, -+{0x56D9, 0x00}, -+{0x56DA, 0x80}, -+{0x56DB, 0x00}, -+{0x56DC, 0x00}, -+{0x56E8, 0x00}, -+{0x56E9, 0x7F}, -+{0x56EA, 0x00}, -+{0x56EB, 0x7F}, -+{0x5100, 0x00}, -+{0x5101, 0x80}, -+{0x5102, 0x00}, -+{0x5103, 0x80}, -+{0x5104, 0x00}, -+{0x5105, 0x80}, -+{0x5106, 0x00}, -+{0x5107, 0x80}, -+{0x5108, 0x00}, -+{0x5109, 0x00}, -+{0x510A, 0x00}, -+{0x510B, 0x00}, -+{0x510C, 0x00}, -+{0x510D, 0x00}, -+{0x510E, 0x00}, -+{0x510F, 0x00}, -+{0x5110, 0x00}, -+{0x5111, 0x80}, -+{0x5112, 0x00}, -+{0x5113, 0x80}, -+{0x5114, 0x00}, -+{0x5115, 0x80}, -+{0x5116, 0x00}, -+{0x5117, 0x80}, -+{0x5118, 0x00}, -+{0x5119, 0x00}, -+{0x511A, 0x00}, -+{0x511B, 0x00}, -+{0x511C, 0x00}, -+{0x511D, 0x00}, -+{0x511E, 0x00}, -+{0x511F, 0x00}, -+{0x56D0, 0x00}, -+{0x5006, 0x04}, -+{0x5608, 0x05}, -+{0x52D7, 0x06}, -+{0x528D, 0x08}, -+{0x5293, 0x12}, -+{0x52D3, 0x12}, -+{0x5288, 0x06}, -+{0x5289, 0x20}, -+{0x52C8, 0x06}, -+{0x52C9, 0x20}, -+{0x52CD, 0x04}, -+{0x5381, 0x00}, -+{0x5382, 0xFF}, -+{0x5589, 0x76}, -+{0x558A, 0x47}, -+{0x558B, 0xEF}, -+{0x558C, 0xC9}, -+{0x558D, 0x49}, -+{0x558E, 0x30}, -+{0x558F, 0x67}, -+{0x5590, 0x3F}, -+{0x5591, 0xF0}, -+{0x5592, 0x10}, -+{0x55A2, 0x6D}, -+{0x55A3, 0x55}, -+{0x55A4, 0xC3}, -+{0x55A5, 0xB5}, -+{0x55A6, 0x43}, -+{0x55A7, 0x38}, -+{0x55A8, 0x5F}, -+{0x55A9, 0x4B}, -+{0x55AA, 0xF0}, -+{0x55AB, 0x10}, -+{0x5581, 0x52}, -+{0x5300, 0x01}, -+{0x5301, 0x00}, -+{0x5302, 0x00}, -+{0x5303, 0x0E}, -+{0x5304, 0x00}, -+{0x5305, 0x0E}, -+{0x5306, 0x00}, -+{0x5307, 0x36}, -+{0x5308, 0x00}, -+{0x5309, 0xD9}, -+{0x530A, 0x00}, -+{0x530B, 0x0F}, -+{0x530C, 0x00}, -+{0x530D, 0x2C}, -+{0x530E, 0x00}, -+{0x530F, 0x59}, -+{0x5310, 0x00}, -+{0x5311, 0x7B}, -+{0x5312, 0x00}, -+{0x5313, 0x22}, -+{0x5314, 0x00}, -+{0x5315, 0xD5}, -+{0x5316, 0x00}, -+{0x5317, 0x13}, -+{0x5318, 0x00}, -+{0x5319, 0x18}, -+{0x531A, 0x00}, -+{0x531B, 0x26}, -+{0x531C, 0x00}, -+{0x531D, 0xDC}, -+{0x531E, 0x00}, -+{0x531F, 0x02}, -+{0x5320, 0x00}, -+{0x5321, 0x24}, -+{0x5322, 0x00}, -+{0x5323, 0x56}, -+{0x5324, 0x00}, -+{0x5325, 0x85}, -+{0x5326, 0x00}, -+{0x5327, 0x20}, -+{0x5609, 0x01}, -+{0x560A, 0x40}, -+{0x560B, 0x01}, -+{0x560C, 0x40}, -+{0x560D, 0x00}, -+{0x560E, 0xFA}, -+{0x560F, 0x00}, -+{0x5610, 0xFA}, -+{0x5611, 0x02}, -+{0x5612, 0x80}, -+{0x5613, 0x02}, -+{0x5614, 0x80}, -+{0x5615, 0x01}, -+{0x5616, 0x2C}, -+{0x5617, 0x01}, -+{0x5618, 0x2C}, -+{0x563B, 0x01}, -+{0x563C, 0x01}, -+{0x563D, 0x01}, -+{0x563E, 0x01}, -+{0x563F, 0x03}, -+{0x5640, 0x03}, -+{0x5641, 0x03}, -+{0x5642, 0x05}, -+{0x5643, 0x09}, -+{0x5644, 0x05}, -+{0x5645, 0x05}, -+{0x5646, 0x05}, -+{0x5647, 0x05}, -+{0x5651, 0x00}, -+{0x5652, 0x80}, -+{0x521A, 0x01}, -+{0x521B, 0x03}, -+{0x521C, 0x06}, -+{0x521D, 0x0A}, -+{0x521E, 0x0E}, -+{0x521F, 0x12}, -+{0x5220, 0x16}, -+{0x5223, 0x02}, -+{0x5225, 0x04}, -+{0x5227, 0x08}, -+{0x5229, 0x0C}, -+{0x522B, 0x12}, -+{0x522D, 0x18}, -+{0x522F, 0x1E}, -+{0x5241, 0x04}, -+{0x5242, 0x01}, -+{0x5243, 0x03}, -+{0x5244, 0x06}, -+{0x5245, 0x0A}, -+{0x5246, 0x0E}, -+{0x5247, 0x12}, -+{0x5248, 0x16}, -+{0x524A, 0x03}, -+{0x524C, 0x04}, -+{0x524E, 0x08}, -+{0x5250, 0x0C}, -+{0x5252, 0x12}, -+{0x5254, 0x18}, -+{0x5256, 0x1E}, -+{0x4606, (2*OV10635_HTS) >> 8}, /* fifo_line_length = 2*hts */ -+{0x4607, (2*OV10635_HTS) & 0xff}, -+{0x460a, (2*(OV10635_HTS-OV10635_MAX_WIDTH)) >> 8}, /* fifo_hsync_start = 2*(hts - xres) */ -+{0x460b, (2*(OV10635_HTS-OV10635_MAX_WIDTH)) & 0xff }, -+{0x460C, 0x00}, -+{0x4620, 0x0E}, -+#if 0 -+{0x4700, 0x02}, // BT656: mode is acceptable but artefact lines on left/bottom due to BT656 SAV/EAV are parsed as image data -+#else -+{0x4700, 0x04}, // BT601: 0x08 is also accaptable as HS/VS mode -+#endif -+{0x4701, 0x00}, -+{0x4702, 0x01}, -+{0x4004, 0x04}, -+{0x4005, 0x18}, -+{0x4001, 0x06}, -+{0x4050, 0x22}, -+{0x4051, 0x24}, -+{0x4052, 0x02}, -+{0x4057, 0x9C}, -+{0x405A, 0x00}, -+{0x4202, 0x02}, -+{0x3023, 0x10}, -+{0x0100, 0x01}, -+{0x0100, 0x01}, -+{0x6F10, 0x07}, -+{0x6F11, 0x82}, -+{0x6F12, 0x04}, -+{0x6F13, 0x00}, -+{0xD000, 0x19}, -+{0xD001, 0xA0}, -+{0xD002, 0x00}, -+{0xD003, 0x01}, -+{0xD004, 0xA9}, -+{0xD005, 0xAD}, -+{0xD006, 0x10}, -+{0xD007, 0x40}, -+{0xD008, 0x44}, -+{0xD009, 0x00}, -+{0xD00A, 0x68}, -+{0xD00B, 0x00}, -+{0xD00C, 0x15}, -+{0xD00D, 0x00}, -+{0xD00E, 0x00}, -+{0xD00F, 0x00}, -+{0xD040, 0x9C}, -+{0xD041, 0x21}, -+{0xD042, 0xFF}, -+{0xD043, 0xF8}, -+{0xD044, 0xD4}, -+{0xD045, 0x01}, -+{0xD046, 0x48}, -+{0xD047, 0x00}, -+{0xD048, 0xD4}, -+{0xD049, 0x01}, -+{0xD04A, 0x50}, -+{0xD04B, 0x04}, -+{0xD04C, 0x18}, -+{0xD04D, 0x60}, -+{0xD04E, 0x00}, -+{0xD04F, 0x01}, -+{0xD050, 0xA8}, -+{0xD051, 0x63}, -+{0xD052, 0x02}, -+{0xD053, 0xA4}, -+{0xD054, 0x85}, -+{0xD055, 0x43}, -+{0xD056, 0x00}, -+{0xD057, 0x00}, -+{0xD058, 0x18}, -+{0xD059, 0x60}, -+{0xD05A, 0x00}, -+{0xD05B, 0x01}, -+{0xD05C, 0xA8}, -+{0xD05D, 0x63}, -+{0xD05E, 0x03}, -+{0xD05F, 0xF0}, -+{0xD060, 0x98}, -+{0xD061, 0xA3}, -+{0xD062, 0x00}, -+{0xD063, 0x00}, -+{0xD064, 0x8C}, -+{0xD065, 0x6A}, -+{0xD066, 0x00}, -+{0xD067, 0x6E}, -+{0xD068, 0xE5}, -+{0xD069, 0x85}, -+{0xD06A, 0x18}, -+{0xD06B, 0x00}, -+{0xD06C, 0x10}, -+{0xD06D, 0x00}, -+{0xD06E, 0x00}, -+{0xD06F, 0x10}, -+{0xD070, 0x9C}, -+{0xD071, 0x80}, -+{0xD072, 0x00}, -+{0xD073, 0x03}, -+{0xD074, 0x18}, -+{0xD075, 0x60}, -+{0xD076, 0x00}, -+{0xD077, 0x01}, -+{0xD078, 0xA8}, -+{0xD079, 0x63}, -+{0xD07A, 0x07}, -+{0xD07B, 0x80}, -+{0xD07C, 0x07}, -+{0xD07D, 0xFF}, -+{0xD07E, 0xF9}, -+{0xD07F, 0x03}, -+{0xD080, 0x8C}, -+{0xD081, 0x63}, -+{0xD082, 0x00}, -+{0xD083, 0x00}, -+{0xD084, 0xA5}, -+{0xD085, 0x6B}, -+{0xD086, 0x00}, -+{0xD087, 0xFF}, -+{0xD088, 0x18}, -+{0xD089, 0x80}, -+{0xD08A, 0x00}, -+{0xD08B, 0x01}, -+{0xD08C, 0xA8}, -+{0xD08D, 0x84}, -+{0xD08E, 0x01}, -+{0xD08F, 0x04}, -+{0xD090, 0xE1}, -+{0xD091, 0x6B}, -+{0xD092, 0x58}, -+{0xD093, 0x00}, -+{0xD094, 0x94}, -+{0xD095, 0x6A}, -+{0xD096, 0x00}, -+{0xD097, 0x70}, -+{0xD098, 0xE1}, -+{0xD099, 0x6B}, -+{0xD09A, 0x20}, -+{0xD09B, 0x00}, -+{0xD09C, 0x95}, -+{0xD09D, 0x6B}, -+{0xD09E, 0x00}, -+{0xD09F, 0x00}, -+{0xD0A0, 0xE4}, -+{0xD0A1, 0x8B}, -+{0xD0A2, 0x18}, -+{0xD0A3, 0x00}, -+{0xD0A4, 0x0C}, -+{0xD0A5, 0x00}, -+{0xD0A6, 0x00}, -+{0xD0A7, 0x23}, -+{0xD0A8, 0x15}, -+{0xD0A9, 0x00}, -+{0xD0AA, 0x00}, -+{0xD0AB, 0x00}, -+{0xD0AC, 0x18}, -+{0xD0AD, 0x60}, -+{0xD0AE, 0x80}, -+{0xD0AF, 0x06}, -+{0xD0B0, 0xA8}, -+{0xD0B1, 0x83}, -+{0xD0B2, 0x40}, -+{0xD0B3, 0x08}, -+{0xD0B4, 0xA8}, -+{0xD0B5, 0xE3}, -+{0xD0B6, 0x38}, -+{0xD0B7, 0x2A}, -+{0xD0B8, 0xA8}, -+{0xD0B9, 0xC3}, -+{0xD0BA, 0x40}, -+{0xD0BB, 0x09}, -+{0xD0BC, 0xA8}, -+{0xD0BD, 0xA3}, -+{0xD0BE, 0x38}, -+{0xD0BF, 0x29}, -+{0xD0C0, 0x8C}, -+{0xD0C1, 0x65}, -+{0xD0C2, 0x00}, -+{0xD0C3, 0x00}, -+{0xD0C4, 0xD8}, -+{0xD0C5, 0x04}, -+{0xD0C6, 0x18}, -+{0xD0C7, 0x00}, -+{0xD0C8, 0x8C}, -+{0xD0C9, 0x67}, -+{0xD0CA, 0x00}, -+{0xD0CB, 0x00}, -+{0xD0CC, 0xD8}, -+{0xD0CD, 0x06}, -+{0xD0CE, 0x18}, -+{0xD0CF, 0x00}, -+{0xD0D0, 0x18}, -+{0xD0D1, 0x60}, -+{0xD0D2, 0x80}, -+{0xD0D3, 0x06}, -+{0xD0D4, 0xA8}, -+{0xD0D5, 0xE3}, -+{0xD0D6, 0x67}, -+{0xD0D7, 0x02}, -+{0xD0D8, 0xA9}, -+{0xD0D9, 0x03}, -+{0xD0DA, 0x67}, -+{0xD0DB, 0x03}, -+{0xD0DC, 0xA8}, -+{0xD0DD, 0xC3}, -+{0xD0DE, 0x3D}, -+{0xD0DF, 0x05}, -+{0xD0E0, 0x8C}, -+{0xD0E1, 0x66}, -+{0xD0E2, 0x00}, -+{0xD0E3, 0x00}, -+{0xD0E4, 0xB8}, -+{0xD0E5, 0x63}, -+{0xD0E6, 0x00}, -+{0xD0E7, 0x18}, -+{0xD0E8, 0xB8}, -+{0xD0E9, 0x63}, -+{0xD0EA, 0x00}, -+{0xD0EB, 0x98}, -+{0xD0EC, 0xBC}, -+{0xD0ED, 0x03}, -+{0xD0EE, 0x00}, -+{0xD0EF, 0x00}, -+{0xD0F0, 0x10}, -+{0xD0F1, 0x00}, -+{0xD0F2, 0x00}, -+{0xD0F3, 0x16}, -+{0xD0F4, 0xB8}, -+{0xD0F5, 0x83}, -+{0xD0F6, 0x00}, -+{0xD0F7, 0x19}, -+{0xD0F8, 0x8C}, -+{0xD0F9, 0x67}, -+{0xD0FA, 0x00}, -+{0xD0FB, 0x00}, -+{0xD0FC, 0xB8}, -+{0xD0FD, 0xA4}, -+{0xD0FE, 0x00}, -+{0xD0FF, 0x98}, -+{0xD100, 0xB8}, -+{0xD101, 0x83}, -+{0xD102, 0x00}, -+{0xD103, 0x08}, -+{0xD104, 0x8C}, -+{0xD105, 0x68}, -+{0xD106, 0x00}, -+{0xD107, 0x00}, -+{0xD108, 0xE0}, -+{0xD109, 0x63}, -+{0xD10A, 0x20}, -+{0xD10B, 0x04}, -+{0xD10C, 0xE0}, -+{0xD10D, 0x65}, -+{0xD10E, 0x18}, -+{0xD10F, 0x00}, -+{0xD110, 0xA4}, -+{0xD111, 0x83}, -+{0xD112, 0xFF}, -+{0xD113, 0xFF}, -+{0xD114, 0xB8}, -+{0xD115, 0x64}, -+{0xD116, 0x00}, -+{0xD117, 0x48}, -+{0xD118, 0xD8}, -+{0xD119, 0x07}, -+{0xD11A, 0x18}, -+{0xD11B, 0x00}, -+{0xD11C, 0xD8}, -+{0xD11D, 0x08}, -+{0xD11E, 0x20}, -+{0xD11F, 0x00}, -+{0xD120, 0x9C}, -+{0xD121, 0x60}, -+{0xD122, 0x00}, -+{0xD123, 0x00}, -+{0xD124, 0xD8}, -+{0xD125, 0x06}, -+{0xD126, 0x18}, -+{0xD127, 0x00}, -+{0xD128, 0x00}, -+{0xD129, 0x00}, -+{0xD12A, 0x00}, -+{0xD12B, 0x08}, -+{0xD12C, 0x15}, -+{0xD12D, 0x00}, -+{0xD12E, 0x00}, -+{0xD12F, 0x00}, -+{0xD130, 0x8C}, -+{0xD131, 0x6A}, -+{0xD132, 0x00}, -+{0xD133, 0x76}, -+{0xD134, 0xBC}, -+{0xD135, 0x23}, -+{0xD136, 0x00}, -+{0xD137, 0x00}, -+{0xD138, 0x13}, -+{0xD139, 0xFF}, -+{0xD13A, 0xFF}, -+{0xD13B, 0xE6}, -+{0xD13C, 0x18}, -+{0xD13D, 0x60}, -+{0xD13E, 0x80}, -+{0xD13F, 0x06}, -+{0xD140, 0x03}, -+{0xD141, 0xFF}, -+{0xD142, 0xFF}, -+{0xD143, 0xDD}, -+{0xD144, 0xA8}, -+{0xD145, 0x83}, -+{0xD146, 0x40}, -+{0xD147, 0x08}, -+{0xD148, 0x85}, -+{0xD149, 0x21}, -+{0xD14A, 0x00}, -+{0xD14B, 0x00}, -+{0xD14C, 0x85}, -+{0xD14D, 0x41}, -+{0xD14E, 0x00}, -+{0xD14F, 0x04}, -+{0xD150, 0x44}, -+{0xD151, 0x00}, -+{0xD152, 0x48}, -+{0xD153, 0x00}, -+{0xD154, 0x9C}, -+{0xD155, 0x21}, -+{0xD156, 0x00}, -+{0xD157, 0x08}, -+{0x6F0E, 0x03}, -+{0x6F0F, 0x00}, -+{0x460E, 0x08}, -+{0x460F, 0x01}, -+{0x4610, 0x00}, -+{0x4611, 0x01}, -+{0x4612, 0x00}, -+{0x4613, 0x01}, -+{0x4605, 0x08}, // 8bit -+//{0x4709, 0x10}, // swap data bits order [9:0] -> [0:9] -+{0x4608, 0x00}, -+{0x4609, 0x08}, -+{0x6804, 0x00}, -+{0x6805, 0x06}, -+{0x6806, 0x00}, -+{0x5120, 0x00}, -+{0x3510, 0x00}, -+{0x3504, 0x00}, -+{0x6800, 0x00}, -+{0x6F0D, 0x01}, -+{0x4708, 0x01}, // PCLK rising edge -+{0x5000, 0xFF}, -+{0x5001, 0xBF}, -+{0x5002, 0x7E}, -+#ifdef OV10635_DISPLAY_PATTERN -+{0x503d, 0x80}, -+#else -+{0x503D, 0x00}, -+#endif -+{0xC450, 0x01}, /* AA mode */ -+{0xC452, 0x04}, -+{0xC453, 0x00}, -+{0xC454, 0x00}, -+{0xC455, 0x01}, -+{0xC456, 0x01}, -+{0xC457, 0x00}, -+{0xC458, 0x00}, -+{0xC459, 0x00}, -+{0xC45B, 0x00}, -+{0xC45C, 0x01}, -+{0xC45D, 0x00}, -+{0xC45E, 0x00}, -+{0xC45F, 0x00}, -+{0xC460, 0x00}, -+{0xC461, 0x01}, -+{0xC462, 0x01}, -+{0xC464, 0x03}, -+{0xC465, 0x00}, -+{0xC466, 0x8A}, -+{0xC467, 0x00}, -+{0xC468, 0x86}, -+{0xC469, 0x00}, -+{0xC46A, 0x30}, -+{0xC46B, 0x50}, -+{0xC46C, 0x30}, -+{0xC46D, 0x28}, -+{0xC46E, 0x60}, -+{0xC46F, 0x40}, -+{0xC47C, 0x01}, -+{0xC47D, 0x38}, -+{0xC47E, 0x00}, -+{0xC47F, 0x00}, -+{0xC480, 0x00}, -+{0xC481, 0xFF}, -+{0xC482, 0x00}, -+{0xC483, 0x40}, -+{0xC484, 0x00}, -+{0xC485, 0x18}, -+{0xC486, 0x00}, -+{0xC487, 0x18}, -+{0xC488, (OV10635_VTS-8)*16 >> 8}, -+{0xC489, (OV10635_VTS-8)*16 & 0xff}, -+{0xC48A, (OV10635_VTS-8)*16 >> 8}, -+{0xC48B, (OV10635_VTS-8)*16 & 0xff}, -+{0xC48C, 0x00}, -+{0xC48D, 0x04}, -+{0xC48E, 0x00}, -+{0xC48F, 0x04}, -+{0xC490, 0x03}, -+{0xC492, 0x20}, -+{0xC493, 0x08}, -+{0xC498, 0x02}, -+{0xC499, 0x00}, -+{0xC49A, 0x02}, -+{0xC49B, 0x00}, -+{0xC49C, 0x02}, -+{0xC49D, 0x00}, -+{0xC49E, 0x02}, -+{0xC49F, 0x60}, -+{0xC4A0, 0x03}, -+{0xC4A1, 0x00}, -+{0xC4A2, 0x04}, -+{0xC4A3, 0x00}, -+{0xC4A4, 0x00}, -+{0xC4A5, 0x10}, -+{0xC4A6, 0x00}, -+{0xC4A7, 0x40}, -+{0xC4A8, 0x00}, -+{0xC4A9, 0x80}, -+{0xC4AA, 0x0D}, -+{0xC4AB, 0x00}, -+{0xC4AC, 0x0F}, -+{0xC4AD, 0xC0}, -+{0xC4B4, 0x01}, -+{0xC4B5, 0x01}, -+{0xC4B6, 0x00}, -+{0xC4B7, 0x01}, -+{0xC4B8, 0x00}, -+{0xC4B9, 0x01}, -+{0xC4BA, 0x01}, -+{0xC4BB, 0x00}, -+{0xC4BC, 0x01}, -+{0xC4BD, 0x60}, -+{0xC4BE, 0x02}, -+{0xC4BF, 0x33}, -+{0xC4C8, 0x03}, -+{0xC4C9, 0xD0}, -+{0xC4CA, 0x0E}, -+{0xC4CB, 0x00}, -+{0xC4CC, 0x0E}, -+{0xC4CD, 0x51}, -+{0xC4CE, 0x0E}, -+{0xC4CF, 0x51}, -+{0xC4D0, 0x04}, -+{0xC4D1, 0x80}, -+{0xC4E0, 0x04}, -+{0xC4E1, 0x02}, -+{0xC4E2, 0x01}, -+{0xC4E4, 0x10}, -+{0xC4E5, 0x20}, -+{0xC4E6, 0x30}, -+{0xC4E7, 0x40}, -+{0xC4E8, 0x50}, -+{0xC4E9, 0x60}, -+{0xC4EA, 0x70}, -+{0xC4EB, 0x80}, -+{0xC4EC, 0x90}, -+{0xC4ED, 0xA0}, -+{0xC4EE, 0xB0}, -+{0xC4EF, 0xC0}, -+{0xC4F0, 0xD0}, -+{0xC4F1, 0xE0}, -+{0xC4F2, 0xF0}, -+{0xC4F3, 0x80}, -+{0xC4F4, 0x00}, -+{0xC4F5, 0x20}, -+{0xC4F6, 0x02}, -+{0xC4F7, 0x00}, -+{0xC4F8, 0x00}, -+{0xC4F9, 0x00}, -+{0xC4FA, 0x00}, -+{0xC4FB, 0x01}, -+{0xC4FC, 0x01}, -+{0xC4FD, 0x00}, -+{0xC4FE, 0x04}, -+{0xC4FF, 0x02}, -+{0xC500, 0x48}, -+{0xC501, 0x74}, -+{0xC502, 0x58}, -+{0xC503, 0x80}, -+{0xC504, 0x05}, -+{0xC505, 0x80}, -+{0xC506, 0x03}, -+{0xC507, 0x80}, -+{0xC508, 0x01}, -+{0xC509, 0xC0}, -+{0xC50A, 0x01}, -+{0xC50B, 0xA0}, -+{0xC50C, 0x01}, -+{0xC50D, 0x2C}, -+{0xC50E, 0x01}, -+{0xC50F, 0x0A}, -+{0xC510, 0x00}, -+{0xC511, 0x00}, -+{0xC512, 0xE5}, -+{0xC513, 0x14}, -+{0xC514, 0x04}, -+{0xC515, 0x00}, -+{0xC518, OV10635_VTS >> 8}, -+{0xC519, OV10635_VTS & 0xff}, -+{0xC51A, OV10635_HTS >> 8}, -+{0xC51B, OV10635_HTS & 0xff}, -+{0xC2E0, 0x00}, -+{0xC2E1, 0x51}, -+{0xC2E2, 0x00}, -+{0xC2E3, 0xD6}, -+{0xC2E4, 0x01}, -+{0xC2E5, 0x5E}, -+{0xC2E9, 0x01}, -+{0xC2EA, 0x7A}, -+{0xC2EB, 0x90}, -+{0xC2ED, 0x00}, -+{0xC2EE, 0x7A}, -+{0xC2EF, 0x64}, -+{0xC308, 0x00}, -+{0xC309, 0x00}, -+{0xC30A, 0x00}, -+{0xC30C, 0x00}, -+{0xC30D, 0x01}, -+{0xC30E, 0x00}, -+{0xC30F, 0x00}, -+{0xC310, 0x01}, -+{0xC311, 0x60}, -+{0xC312, 0xFF}, -+{0xC313, 0x08}, -+{0xC314, 0x01}, -+{0xC315, 0x00}, /* min saturation gain */ -+{0xC316, 0xFF}, /* max saturation gain */ -+{0xC317, 0x0B}, -+{0xC318, 0x00}, -+{0xC319, 0x0C}, -+{0xC31A, 0x00}, -+{0xC31B, 0xE0}, -+{0xC31C, 0x00}, -+{0xC31D, 0x14}, -+{0xC31E, 0x00}, -+{0xC31F, 0xC5}, -+{0xC320, 0xFF}, -+{0xC321, 0x4B}, -+{0xC322, 0xFF}, -+{0xC323, 0xF0}, -+{0xC324, 0xFF}, -+{0xC325, 0xE8}, -+{0xC326, 0x00}, -+{0xC327, 0x46}, -+{0xC328, 0xFF}, -+{0xC329, 0xD2}, -+{0xC32A, 0xFF}, -+{0xC32B, 0xE4}, -+{0xC32C, 0xFF}, -+{0xC32D, 0xBB}, -+{0xC32E, 0x00}, -+{0xC32F, 0x61}, -+{0xC330, 0xFF}, -+{0xC331, 0xF9}, -+{0xC332, 0x00}, -+{0xC333, 0xD9}, -+{0xC334, 0x00}, -+{0xC335, 0x2E}, -+{0xC336, 0x00}, -+{0xC337, 0xB1}, -+{0xC338, 0xFF}, -+{0xC339, 0x64}, -+{0xC33A, 0xFF}, -+{0xC33B, 0xEB}, -+{0xC33C, 0xFF}, -+{0xC33D, 0xE8}, -+{0xC33E, 0x00}, -+{0xC33F, 0x48}, -+{0xC340, 0xFF}, -+{0xC341, 0xD0}, -+{0xC342, 0xFF}, -+{0xC343, 0xED}, -+{0xC344, 0xFF}, -+{0xC345, 0xAD}, -+{0xC346, 0x00}, -+{0xC347, 0x66}, -+{0xC348, 0x01}, -+{0xC349, 0x00}, -+{0x6700, 0x04}, -+{0x6701, 0x7B}, -+{0x6702, 0xFD}, -+{0x6703, 0xF9}, -+{0x6704, 0x3D}, -+{0x6705, 0x71}, -+{0x6706, 0x78}, -+{0x6708, 0x05}, -+{0x6F06, 0x6F}, -+{0x6F07, 0x00}, -+{0x6F0A, 0x6F}, -+{0x6F0B, 0x00}, -+{0x6F00, 0x03}, -+{0xC34C, 0x01}, -+{0xC34D, 0x00}, -+{0xC34E, 0x46}, -+{0xC34F, 0x55}, -+{0xC350, 0x00}, -+{0xC351, 0x40}, -+{0xC352, 0x00}, -+{0xC353, 0xFF}, -+{0xC354, 0x04}, -+{0xC355, 0x08}, -+{0xC356, 0x01}, -+{0xC357, 0xEF}, -+{0xC358, 0x30}, -+{0xC359, 0x01}, -+{0xC35A, 0x64}, -+{0xC35B, 0x46}, -+{0xC35C, 0x00}, -+{0x3042, 0xF0}, -+{0x3042, 0xF0}, -+{0x3042, 0xF0}, -+{0x3042, 0xF0}, -+{0x3042, 0xF0}, -+{0x3042, 0xF0}, -+{0x3042, 0xF0}, -+{0x3042, 0xF0}, -+{0x3042, 0xF0}, -+{0x3042, 0xF0}, -+{0x3042, 0xF0}, -+{0x3042, 0xF0}, -+{0x3042, 0xF0}, -+{0x3042, 0xF0}, -+{0x3042, 0xF0}, -+{0x3042, 0xF0}, -+{0x3042, 0xF0}, -+{0x3042, 0xF0}, -+{0x3042, 0xF0}, -+{0x3042, 0xF0}, -+{0x3042, 0xF0}, -+{0x3042, 0xF0}, -+{0x3042, 0xF0}, -+{0x3042, 0xF0}, -+{0x3042, 0xF0}, -+{0x3042, 0xF0}, -+{0xC261, 0x01}, -+{0x301B, 0xF0}, -+{0x301C, 0xF0}, -+{0x301A, 0xF0}, -+{0x6F00, 0xC3}, -+{0xC46A, 0x30}, -+{0xC46D, 0x20}, -+{0xC464, 0x84}, -+{0xC465, 0x00}, -+{0x6F00, 0x03}, -+{0x6F00, 0x43}, -+{0x381C, 0x00}, -+{0x381D, 0x40}, -+{0xC454, 0x01}, -+{0x6F00, 0xC3}, -+{0xC454, 0x00}, -+{0xC4B1, 0x02}, -+{0xC4B2, 0x01}, -+{0xC4B3, 0x03}, -+{0x6F00, 0x03}, -+{0x6F00, 0x43}, -+/* enable FSIN (FRAMESYNC input) functionality */ -+{0x3832, (0x0d+2*0x20+0x15+38) >> 8}, -+{0x3833, (0x0d+2*0x20+0x15+38) & 0xff}, -+{0x3834, OV10635_VTS >> 8}, -+{0x3835, OV10635_VTS & 0xff}, -+{0x302E, 0x01}, -+}; -+ -+static const struct ov10635_reg ov10635_regs_30fps[] = { -+/* disable clocks */ -+{0x301b, 0xff}, -+{0x301c, 0xff}, -+{0x301a, 0xff}, -+/* clk = 24Mhz/2*32/2(1+1)=96Mhz, 30fps */ -+{0x3003, 0x20}, -+{0x3004, 0x21}, -+/* enable clocks */ -+{0x301b, 0xf0}, -+{0x301c, 0xf0}, -+{0x301a, 0xf0}, -+}; -+ -+static const struct ov10635_reg ov10635_regs_15fps[] = { -+/* disable clocks */ -+{0x301b, 0xff}, -+{0x301c, 0xff}, -+{0x301a, 0xff}, -+/* clk = 24Mhz/2*32/2(1+3)=48Mhz, 15fps */ -+{0x3003, 0x20}, -+{0x3004, 0x23}, -+/* enable clocks */ -+{0x301b, 0xf0}, -+{0x301c, 0xf0}, -+{0x301a, 0xf0}, -+}; -+ -+static const struct ov10635_reg ov10635_regs_10fps[] = { -+/* disable clocks */ -+{0x301b, 0xff}, -+{0x301c, 0xff}, -+{0x301a, 0xff}, -+/* clk = 24Mhz/2*32/2(1+5)=32Mhz, 10fps */ -+{0x3003, 0x20}, -+{0x3004, 0x25}, -+/* enable clocks */ -+{0x301b, 0xf0}, -+{0x301c, 0xf0}, -+{0x301a, 0xf0}, -+}; -+ -+static const struct ov10635_reg ov10635_regs_5fps[] = { -+/* disable clocks */ -+{0x301b, 0xff}, -+{0x301c, 0xff}, -+{0x301a, 0xff}, -+/* clk = 24Mhz/4*32/2(1+5)=96Mhz, 5fps */ -+{0x3003, 0x20}, -+{0x3004, 0x45}, -+/* enable clocks */ -+{0x301b, 0xf0}, -+{0x301c, 0xf0}, -+{0x301a, 0xf0}, -+}; -+ -+static const struct ov10635_reg ov10635_regs_contrast[5][18] = { -+{ -+ {0x6f00, 0xc3}, -+ {0xc4e4, 0x20}, -+ {0xc4e5, 0x40}, -+ {0xc4e6, 0x60}, -+ {0xc4e7, 0x80}, -+ {0xc4e8, 0xa0}, -+ {0xc4e9, 0xb4}, -+ {0xc4ea, 0xc0}, -+ {0xc4eb, 0xcb}, -+ {0xc4ec, 0xd5}, -+ {0xc4ed, 0xde}, -+ {0xc4ee, 0xe6}, -+ {0xc4ef, 0xed}, -+ {0xc4f0, 0xf3}, -+ {0xc4f1, 0xf8}, -+ {0xc4f2, 0xfc}, -+ {0x6f00, 0x03}, -+ {0x6f00, 0x43}, -+}, { -+ {0x6f00, 0xc3}, -+ {0xc4e4, 0x18}, -+ {0xc4e5, 0x30}, -+ {0xc4e6, 0x48}, -+ {0xc4e7, 0x60}, -+ {0xc4e8, 0x78}, -+ {0xc4e9, 0x90}, -+ {0xc4ea, 0xa4}, -+ {0xc4eb, 0xb4}, -+ {0xc4ec, 0xc2}, -+ {0xc4ed, 0xcf}, -+ {0xc4ee, 0xdb}, -+ {0xc4ef, 0xe5}, -+ {0xc4f0, 0xee}, -+ {0xc4f1, 0xf6}, -+ {0xc4f2, 0xfc}, -+ {0x6f00, 0x03}, -+ {0x6f00, 0x43}, -+}, { -+ {0x6f00, 0xc3}, -+ {0xc4e4, 0x10}, -+ {0xc4e5, 0x20}, -+ {0xc4e6, 0x30}, -+ {0xc4e7, 0x40}, -+ {0xc4e8, 0x50}, -+ {0xc4e9, 0x60}, -+ {0xc4ea, 0x70}, -+ {0xc4eb, 0x80}, -+ {0xc4ec, 0x90}, -+ {0xc4ed, 0xa0}, -+ {0xc4ee, 0xb0}, -+ {0xc4ef, 0xc0}, -+ {0xc4f0, 0xd0}, -+ {0xc4f1, 0xe0}, -+ {0xc4f2, 0xf0}, -+ {0x6f00, 0x03}, -+ {0x6f00, 0x43}, -+}, { -+ {0x6f00, 0xc3}, -+ {0xc4e4, 0x0c}, -+ {0xc4e5, 0x18}, -+ {0xc4e6, 0x24}, -+ {0xc4e7, 0x30}, -+ {0xc4e8, 0x3c}, -+ {0xc4e9, 0x48}, -+ {0xc4ea, 0x54}, -+ {0xc4eb, 0x62}, -+ {0xc4ec, 0x72}, -+ {0xc4ed, 0x84}, -+ {0xc4ee, 0x94}, -+ {0xc4ef, 0xa6}, -+ {0xc4f0, 0xb9}, -+ {0xc4f1, 0xcd}, -+ {0xc4f2, 0xe2}, -+ {0x6f00, 0x03}, -+ {0x6f00, 0x43}, -+}, { -+ {0x6f00, 0xc3}, -+ {0xc4e4, 0x06}, -+ {0xc4e5, 0x0d}, -+ {0xc4e6, 0x15}, -+ {0xc4e7, 0x1e}, -+ {0xc4e8, 0x28}, -+ {0xc4e9, 0x32}, -+ {0xc4ea, 0x3c}, -+ {0xc4eb, 0x48}, -+ {0xc4ec, 0x56}, -+ {0xc4ed, 0x66}, -+ {0xc4ee, 0x78}, -+ {0xc4ef, 0x8c}, -+ {0xc4f0, 0xa2}, -+ {0xc4f1, 0xba}, -+ {0xc4f2, 0xd4}, -+ {0x6f00, 0x03}, -+ {0x6f00, 0x43}, -+} -+}; -diff --git a/drivers/media/i2c/soc_camera/ov10635_debug.h b/drivers/media/i2c/soc_camera/ov10635_debug.h -new file mode 100644 -index 0000000..4c3515a ---- /dev/null -+++ b/drivers/media/i2c/soc_camera/ov10635_debug.h -@@ -0,0 +1,54 @@ -+ -+#if 0 -+{0x4700, 0x02}, // BT656 -+{0x381d, 0x40}, // mirror off -+{0x381c, 0x00}, // flip off -+{0x4300, 0x3a}, // YUV: UYVY -+{0x4708, 0x00}, // PCLK rising edge -+ -+// clk = 24Mhz/3*22/2= 88Mhz -+{0x3003, 0x16}, -+{0x3004, 0x30}, -+#endif -+ -+#define WIDTH 1280 -+#define HEIGHT 720 -+ -+// DVP frame size -+{0x3808, WIDTH >> 8}, -+{0x3809, WIDTH & 0xff}, -+{0x380a, HEIGHT >> 8}, -+{0x380b, HEIGHT & 0xff}, -+ -+{0x3802, ((814 - HEIGHT)/2) >> 8}, // vert crop start -+{0x3803, ((814 - HEIGHT)/2) & 0xff}, -+{0x3806, ((814 - HEIGHT)/2 + HEIGHT + 1) >> 8}, // vert crop end -+{0x3807, ((814 - HEIGHT)/2 + HEIGHT + 1) & 0xff}, -+ -+#if 0 -+#define HTS 0x6f6 // got from above table 1782 -+#define VTS (0x2ec+80) // got from above table 748 + 80 -+ -+{0x380c, HTS >> 8}, // hts -+{0x380d, HTS & 0xff}, -+{0x380e, VTS >> 8}, // vts -+{0x380f, VTS & 0xff}, -+ -+// fifo -+{0x4606, (2*HTS) >> 8}, // fifo_line_length = 2*hts -+{0x4607, (2*HTS) & 0xff}, -+{0x460a, (2*(HTS-1280)) >> 8}, // fifo_hsync_start = 2*(hts - xres) -+{0x460b, (2*(HTS-1280)) & 0xff }, -+ -+// exposure -+{0xC488, (VTS-8)*16 >> 8}, -+{0xC489, (VTS-8)*16 & 0xff}, -+{0xC48A, (VTS-8)*16 >> 8}, -+{0xC48B, (VTS-8)*16 & 0xff}, -+ -+// vts/hts -+{0xC518, VTS >> 8}, -+{0xC519, VTS & 0xff}, -+{0xC51A, HTS >> 8}, -+{0xC51B, HTS & 0xff}, -+#endif -diff --git a/drivers/media/i2c/soc_camera/ov106xx.c b/drivers/media/i2c/soc_camera/ov106xx.c -new file mode 100644 -index 0000000..4c797f9 ---- /dev/null -+++ b/drivers/media/i2c/soc_camera/ov106xx.c -@@ -0,0 +1,117 @@ -+/* -+ * OmniVision ov10635/ov490-ov10640/ov495-ov2775 sensor camera driver -+ * -+ * Copyright (C) 2016-2017 Cogent Embedded, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2 of the License, or (at your -+ * option) any later version. -+ */ -+ -+#include "ov10635.c" -+#include "ov490_ov10640.c" -+#include "ov495_ov2775.c" -+#include "ar0132.c" -+#include "ap0101_ar014x.c" -+ -+static enum { -+ ID_OV10635, -+ ID_OV490_OV10640, -+ ID_OV495_OV2775, -+ ID_AR0132, -+ ID_AP0101_AR014X, -+} chip_id; -+ -+static int ov106xx_probe(struct i2c_client *client, -+ const struct i2c_device_id *did) -+{ -+ int ret; -+ chip_id = -EINVAL; -+ -+ ret = ov10635_probe(client, did); -+ if (!ret) { -+ chip_id = ID_OV10635; -+ goto out; -+ } -+ -+ ret = ov490_probe(client, did); -+ if (!ret) { -+ chip_id = ID_OV490_OV10640; -+ goto out; -+ } -+ -+ ret = ov495_probe(client, did); -+ if (!ret) { -+ chip_id = ID_OV495_OV2775; -+ goto out; -+ } -+ -+ ret = ar0132_probe(client, did); -+ if (!ret) { -+ chip_id = ID_AR0132; -+ goto out; -+ } -+ -+ ret = ap0101_probe(client, did); -+ if (!ret) { -+ chip_id = ID_AP0101_AR014X; -+ goto out; -+ } -+ -+ v4l_err(client, "failed to probe @ 0x%02x (%s)\n", -+ client->addr, client->adapter->name); -+out: -+ return ret; -+} -+ -+static int ov106xx_remove(struct i2c_client *client) -+{ -+ switch (chip_id) { -+ case ID_OV10635: -+ ov10635_remove(client); -+ break; -+ case ID_OV490_OV10640: -+ ov490_remove(client); -+ break; -+ case ID_OV495_OV2775: -+ ov495_remove(client); -+ break; -+ case ID_AR0132: -+ ar0132_remove(client); -+ break; -+ case ID_AP0101_AR014X: -+ ap0101_remove(client); -+ break; -+ }; -+ -+ return 0; -+} -+ -+static const struct i2c_device_id ov106xx_id[] = { -+ { "ov106xx", 0 }, -+ { } -+}; -+MODULE_DEVICE_TABLE(i2c, ov106xx_id); -+ -+static const struct of_device_id ov106xx_of_ids[] = { -+ { .compatible = "ovti,ov106xx", }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, ov106xx_of_ids); -+ -+static struct i2c_driver ov106xx_i2c_driver = { -+ .driver = { -+ .name = "ov106xx", -+ .of_match_table = ov106xx_of_ids, -+ }, -+ .probe = ov106xx_probe, -+ .remove = ov106xx_remove, -+ .id_table = ov106xx_id, -+}; -+ -+module_i2c_driver(ov106xx_i2c_driver); -+ -+MODULE_DESCRIPTION("SoC Camera driver for OV10635 or OV490/OV10640 or OV495/OV2775 or AR0132 or AP0101/AR014X"); -+MODULE_AUTHOR("Vladimir Barinov"); -+MODULE_LICENSE("GPL"); -diff --git a/drivers/media/i2c/soc_camera/ov490_ov10640.c b/drivers/media/i2c/soc_camera/ov490_ov10640.c -new file mode 100644 -index 0000000..f1e34a3 ---- /dev/null -+++ b/drivers/media/i2c/soc_camera/ov490_ov10640.c -@@ -0,0 +1,1160 @@ -+/* -+ * OmniVision ov490-ov10640 sensor camera driver -+ * -+ * Copyright (C) 2016-2017 Cogent Embedded, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2 of the License, or (at your -+ * option) any later version. -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include "max9286.h" -+#include "ov490_ov10640.h" -+ -+#define OV490_I2C_ADDR 0x24 -+ -+#define OV490_PID 0x300a -+#define OV490_VER 0x300b -+#define OV490_VERSION_REG 0x0490 -+#define OV490_VERSION(pid, ver) (((pid) << 8) | ((ver) & 0xff)) -+ -+#define OV490_ISP_HSIZE_LOW 0x60 -+#define OV490_ISP_HSIZE_HIGH 0x61 -+#define OV490_ISP_VSIZE_LOW 0x62 -+#define OV490_ISP_VSIZE_HIGH 0x63 -+ -+struct ov490_priv { -+ struct v4l2_subdev sd; -+ struct v4l2_ctrl_handler hdl; -+ struct media_pad pad; -+ struct v4l2_rect rect; -+ int max_width; -+ int max_height; -+ char is_fixed_sensor; -+ int init_complete; -+ u8 id[6]; -+ int exposure; -+ int gain; -+ int autogain; -+ int red; -+ int green_r; -+ int green_b; -+ int blue; -+ int awb; -+ int dvp_order; -+ /* serializers */ -+ int max9286_addr; -+ int max9271_addr; -+ int ti964_addr; -+ int ti954_addr; -+ int ti9x3_addr; -+ int port; -+ int gpio_resetb; -+ int active_low_resetb; -+ int gpio_fsin; -+}; -+ -+static int conf_link; -+module_param(conf_link, int, 0644); -+MODULE_PARM_DESC(conf_link, " Force configuration link. Used only if robust firmware flashing required (f.e. recovery)"); -+ -+static int dvp_order; -+module_param(dvp_order, int, 0644); -+MODULE_PARM_DESC(dvp_order, " DVP bus bits order"); -+ -+static int max_width; -+module_param(max_width, int, 0644); -+MODULE_PARM_DESC(max_width, " Fixed sensor width"); -+ -+static int max_height; -+module_param(max_height, int, 0644); -+MODULE_PARM_DESC(max_height, " Fixed sensor height"); -+ -+static inline struct ov490_priv *to_ov490(const struct i2c_client *client) -+{ -+ return container_of(i2c_get_clientdata(client), struct ov490_priv, sd); -+} -+ -+static void ov490_s_port(struct i2c_client *client, int fwd_en) -+{ -+ struct ov490_priv *priv = to_ov490(client); -+ int tmp_addr; -+ -+ if (priv->max9286_addr) { -+ tmp_addr = client->addr; -+ client->addr = priv->max9286_addr; /* Deserializer I2C address */ -+ reg8_write(client, 0x0a, fwd_en ? 0x11 << priv->port : 0); /* Enable/disable reverse/forward control for this port */ -+ usleep_range(5000, 5500); /* wait 5ms */ -+ client->addr = tmp_addr; -+ }; -+} -+ -+static void ov490_reset(struct i2c_client *client) -+{ -+ struct ov490_priv *priv = to_ov490(client); -+ int tmp_addr; -+ -+ if (priv->max9286_addr) { -+ if (priv->gpio_resetb < 1 || priv->gpio_resetb > 5) -+ return; -+ -+ tmp_addr = client->addr; -+ /* get out from sensor reset */ -+ client->addr = priv->max9271_addr; /* MAX9271 I2C address */ -+ reg8_write(client, 0x0f, (0xfe & ~BIT(priv->gpio_resetb)) | -+ (priv->active_low_resetb ? 0 : BIT(priv->gpio_resetb))); /* set GPIOn value to reset */ -+ usleep_range(2000, 2500); /* wait 2ms */ -+ reg8_write(client, 0x0f, (0xfe & ~BIT(priv->gpio_resetb)) | -+ (priv->active_low_resetb ? BIT(priv->gpio_resetb) : 0)); /* set GPIOn value to un-reset */ -+ usleep_range(2000, 2500); /* wait 2ms */ -+ client->addr = tmp_addr; -+ } -+ -+ if (priv->ti964_addr) { -+ client->addr = priv->ti964_addr; /* TI964 I2C address */ -+ -+ reg8_write(client, 0x4c, (priv->port << 4) | (1 << priv->port)); /* Select RX port number */ -+ usleep_range(2000, 2500); /* wait 2ms */ -+ reg8_write(client, 0x6e, 0x8a); /* set GPIO1 value to reset */ -+ usleep_range(2000, 2500); /* wait 2ms */ -+ reg8_write(client, 0x6e, 0x9a); /* set GPIO1 value to un-reset */ -+ } -+ -+ if (priv->ti954_addr) { -+ client->addr = priv->ti954_addr; /* TI964 I2C address */ -+ -+ reg8_write(client, 0x4c, (priv->port << 4) | (1 << priv->port)); /* Select RX port number */ -+ usleep_range(2000, 2500); /* wait 2ms */ -+ reg8_write(client, 0x6e, 0x8a); /* set GPIO1 value to reset */ -+ usleep_range(2000, 2500); /* wait 2ms */ -+ reg8_write(client, 0x6e, 0x9a); /* set GPIO1 value to un-reset */ -+ } -+} -+ -+static int ov490_set_regs(struct i2c_client *client, -+ const struct ov490_reg *regs, int nr_regs) -+{ -+ int i; -+ -+ for (i = 0; i < nr_regs; i++) { -+ if (reg16_write(client, regs[i].reg, regs[i].val)) { -+ usleep_range(100, 150); /* wait 100 us */ -+ reg16_write(client, regs[i].reg, regs[i].val); -+ } -+ } -+ -+ return 0; -+} -+ -+static u8 ov490_ov10640_read(struct i2c_client *client, u16 addr) -+{ -+ u8 reg_val = 0; -+ -+ reg16_write(client, 0xFFFD, 0x80); -+ usleep_range(100, 150); /* wait 100 us */ -+ reg16_write(client, 0xFFFE, 0x19); -+ usleep_range(100, 150); /* wait 100 us */ -+ reg16_write(client, 0x5000, 0x01); /* read operation */ -+ reg16_write(client, 0x5001, addr >> 8); -+ reg16_write(client, 0x5002, addr & 0xff); -+ reg16_write(client, 0xFFFE, 0x80); -+ usleep_range(100, 150); /* wait 100 us */ -+ reg16_write(client, 0x00C0, 0xc1); -+ reg16_write(client, 0xFFFE, 0x19); -+ usleep_range(1000, 1500); /* wait 1 ms */ -+ reg16_read(client, 0x5000, ®_val); -+ -+ return reg_val; -+} -+ -+static void ov490_ov10640_write(struct i2c_client *client, u16 addr, u8 val) -+{ -+ reg16_write(client, 0xFFFD, 0x80); -+ usleep_range(100, 150); /* wait 100 us */ -+ reg16_write(client, 0xFFFE, 0x19); -+ usleep_range(100, 150); /* wait 100 us */ -+ reg16_write(client, 0x5000, 0x00); /* write operation */ -+ reg16_write(client, 0x5001, addr >> 8); -+ reg16_write(client, 0x5002, addr & 0xff); -+ reg16_write(client, 0x5003, val); -+ reg16_write(client, 0xFFFE, 0x80); -+ usleep_range(100, 150); /* wait 100 us */ -+ reg16_write(client, 0x00C0, 0xc1); -+} -+ -+static int ov490_s_stream(struct v4l2_subdev *sd, int enable) -+{ -+ return 0; -+} -+ -+static int ov490_get_fmt(struct v4l2_subdev *sd, -+ struct v4l2_subdev_pad_config *cfg, -+ struct v4l2_subdev_format *format) ++static int ov10635_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *mf = &format->format; + struct i2c_client *client = v4l2_get_subdevdata(sd); -+ struct ov490_priv *priv = to_ov490(client); ++ struct ov10635_priv *priv = to_ov10635(client); + + if (format->pad) + return -EINVAL; @@ -4839,9 +3249,9 @@ index 0000000..f1e34a3 + return 0; +} + -+static int ov490_set_fmt(struct v4l2_subdev *sd, -+ struct v4l2_subdev_pad_config *cfg, -+ struct v4l2_subdev_format *format) ++static int ov10635_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *mf = &format->format; + @@ -4855,9 +3265,9 @@ index 0000000..f1e34a3 + return 0; +} + -+static int ov490_enum_mbus_code(struct v4l2_subdev *sd, -+ struct v4l2_subdev_pad_config *cfg, -+ struct v4l2_subdev_mbus_code_enum *code) ++static int ov10635_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->pad || code->index > 0) + return -EINVAL; @@ -4867,28 +3277,29 @@ index 0000000..f1e34a3 + return 0; +} + -+static int ov490_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) ++static int ov10635_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); -+ struct ov490_priv *priv = to_ov490(client); ++ struct ov10635_priv *priv = to_ov10635(client); + + memcpy(edid->edid, priv->id, 6); + + edid->edid[6] = 0xff; + edid->edid[7] = client->addr; -+ edid->edid[8] = OV490_VERSION_REG >> 8; -+ edid->edid[9] = OV490_VERSION_REG & 0xff; ++ edid->edid[8] = OV10635_VERSION_REG >> 8; ++ edid->edid[9] = OV10635_VERSION_REG & 0xff; + + return 0; +} + -+static int ov490_set_selection(struct v4l2_subdev *sd, -+ struct v4l2_subdev_pad_config *cfg, -+ struct v4l2_subdev_selection *sel) ++static int ov10635_set_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_selection *sel) +{ + struct v4l2_rect *rect = &sel->r; + struct i2c_client *client = v4l2_get_subdevdata(sd); -+ struct ov490_priv *priv = to_ov490(client); ++ struct ov10635_priv *priv = to_ov10635(client); ++ int subsampling = 0; + + if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || + sel->target != V4L2_SEL_TGT_CROP) @@ -4899,24 +3310,34 @@ index 0000000..f1e34a3 + rect->width = ALIGN(rect->width, 2); + rect->height = ALIGN(rect->height, 2); + -+ if ((rect->left + rect->width > priv->max_width) || -+ (rect->top + rect->height > priv->max_height)) ++ if ((rect->left + rect->width > OV10635_MAX_WIDTH) || ++ (rect->top + rect->height > OV10635_MAX_HEIGHT)) + *rect = priv->rect; + ++ if (rect->width == OV10635_MAX_WIDTH / 2 && ++ rect->height == OV10635_MAX_HEIGHT / 2) ++ subsampling = 1; ++ + priv->rect.left = rect->left; + priv->rect.top = rect->top; + priv->rect.width = rect->width; + priv->rect.height = rect->height; + ++ /* change window only for subsampling, crop is done by VIN */ ++ if (subsampling != priv->subsampling) { ++ ov10635_set_window(sd, subsampling); ++ priv->subsampling = subsampling; ++ } ++ + return 0; +} + -+static int ov490_get_selection(struct v4l2_subdev *sd, -+ struct v4l2_subdev_pad_config *cfg, -+ struct v4l2_subdev_selection *sel) ++static int ov10635_get_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_selection *sel) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); -+ struct ov490_priv *priv = to_ov490(client); ++ struct ov10635_priv *priv = to_ov10635(client); + + if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) + return -EINVAL; @@ -4925,607 +3346,295 @@ index 0000000..f1e34a3 + case V4L2_SEL_TGT_CROP_BOUNDS: + sel->r.left = 0; + sel->r.top = 0; -+ sel->r.width = priv->max_width; -+ sel->r.height = priv->max_height; ++ sel->r.width = OV10635_MAX_WIDTH; ++ sel->r.height = OV10635_MAX_HEIGHT; + return 0; + case V4L2_SEL_TGT_CROP_DEFAULT: + sel->r.left = 0; + sel->r.top = 0; -+ sel->r.width = priv->max_width; -+ sel->r.height = priv->max_height; ++ sel->r.width = OV10635_MAX_WIDTH; ++ sel->r.height = OV10635_MAX_HEIGHT; + return 0; + case V4L2_SEL_TGT_CROP: + sel->r = priv->rect; + return 0; + default: + return -EINVAL; -+ } -+} -+ -+static int ov490_g_mbus_config(struct v4l2_subdev *sd, -+ struct v4l2_mbus_config *cfg) -+{ -+ cfg->flags = V4L2_MBUS_CSI2_1_LANE | V4L2_MBUS_CSI2_CHANNEL_0 | -+ V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; -+ cfg->type = V4L2_MBUS_CSI2; -+ -+ return 0; -+} -+ -+#ifdef CONFIG_VIDEO_ADV_DEBUG -+static int ov490_g_register(struct v4l2_subdev *sd, -+ struct v4l2_dbg_register *reg) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ int ret; -+ u8 val = 0; -+ -+ ret = reg16_read(client, (u16)reg->reg, &val); -+ if (ret < 0) -+ return ret; -+ -+ reg->val = val; -+ reg->size = sizeof(u16); -+ -+ return 0; -+} -+ -+static int ov490_s_register(struct v4l2_subdev *sd, -+ const struct v4l2_dbg_register *reg) -+{ -+ struct i2c_client *client = v4l2_get_subdevdata(sd); -+ int ret; -+ -+ ret = reg16_write(client, (u16)reg->reg, (u8)reg->val); -+ if ((u8)reg->reg == 0xFFFD) -+ usleep_range(100, 150); /* wait 100 us */ -+ if ((u8)reg->reg == 0xFFFE) -+ usleep_range(100, 150); /* wait 100 us */ -+ return ret; ++ } +} -+#endif + -+static struct v4l2_subdev_core_ops ov490_core_ops = { -+#ifdef CONFIG_VIDEO_ADV_DEBUG -+ .g_register = ov490_g_register, -+ .s_register = ov490_s_register, -+#endif -+}; ++static int ov10635_g_mbus_config(struct v4l2_subdev *sd, ++ struct v4l2_mbus_config *cfg) ++{ ++ cfg->flags = V4L2_MBUS_CSI2_1_LANE | V4L2_MBUS_CSI2_CHANNEL_0 | ++ V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; ++ cfg->type = V4L2_MBUS_CSI2; + -+static int ov490_s_gamma(int a, int ref) ++ return 0; ++} ++ ++static int ov10635_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) +{ -+ if ((a + ref) > 0xff) -+ return 0xff; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov10635_priv *priv = to_ov10635(client); ++ struct v4l2_captureparm *cp = &parms->parm.capture; + -+ if ((a + ref) < 0) -+ return 0; ++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; + -+ return a + ref; ++ memset(cp, 0, sizeof(struct v4l2_captureparm)); ++ cp->capability = V4L2_CAP_TIMEPERFRAME; ++ cp->timeperframe.numerator = 1; ++ cp->timeperframe.denominator = priv->fps_denominator; ++ ++ return 0; +} + -+static int ov490_s_ctrl(struct v4l2_ctrl *ctrl) ++static int ov10635_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) +{ -+ struct v4l2_subdev *sd = to_sd(ctrl); + struct i2c_client *client = v4l2_get_subdevdata(sd); -+ struct ov490_priv *priv = to_ov490(client); -+ int ret = -EINVAL; -+ -+ if (!priv->init_complete) -+ return 0; ++ struct ov10635_priv *priv = to_ov10635(client); ++ struct v4l2_captureparm *cp = &parms->parm.capture; ++ int ret = 0; + -+ switch (ctrl->id) { -+ case V4L2_CID_BRIGHTNESS: -+ /* SDE (rough) brightness */ -+ ret = reg16_write(client, 0xFFFD, 0x80); -+ ret |= reg16_write(client, 0xFFFE, 0x19); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x5000, 0x00); -+ ret |= reg16_write(client, 0x5001, ctrl->val); -+ ret |= reg16_write(client, 0xFFFE, 0x80); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x00C0, 0xf1); -+ break; -+ case V4L2_CID_CONTRAST: -+ ret = reg16_write(client, 0xFFFD, 0x80); -+ ret |= reg16_write(client, 0xFFFE, 0x19); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x5000, ctrl->val); -+ ret |= reg16_write(client, 0xFFFE, 0x80); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x00C0, 0xfd); -+ break; -+ case V4L2_CID_SATURATION: -+ ret = reg16_write(client, 0xFFFD, 0x80); -+ ret |= reg16_write(client, 0xFFFE, 0x19); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x5000, ctrl->val); -+ ret |= reg16_write(client, 0xFFFE, 0x80); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x00C0, 0xf3); -+ break; -+ case V4L2_CID_HUE: -+ ret = reg16_write(client, 0xFFFD, 0x80); -+ ret |= reg16_write(client, 0xFFFE, 0x19); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x5000, ctrl->val); -+ ret |= reg16_write(client, 0xFFFE, 0x80); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x00C0, 0xf5); -+ break; -+ case V4L2_CID_GAMMA: -+ ret = reg16_write(client, 0xFFFD, 0x80); -+ ret |= reg16_write(client, 0xFFFE, 0x19); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x5000, ov490_s_gamma(ctrl->val, 0x12)); -+ ret |= reg16_write(client, 0x5001, ov490_s_gamma(ctrl->val, 0x20)); -+ ret |= reg16_write(client, 0x5002, ov490_s_gamma(ctrl->val, 0x3b)); -+ ret |= reg16_write(client, 0x5003, ov490_s_gamma(ctrl->val, 0x5d)); -+ ret |= reg16_write(client, 0x5004, ov490_s_gamma(ctrl->val, 0x6a)); -+ ret |= reg16_write(client, 0x5005, ov490_s_gamma(ctrl->val, 0x76)); -+ ret |= reg16_write(client, 0x5006, ov490_s_gamma(ctrl->val, 0x81)); -+ ret |= reg16_write(client, 0x5007, ov490_s_gamma(ctrl->val, 0x8b)); -+ ret |= reg16_write(client, 0x5008, ov490_s_gamma(ctrl->val, 0x96)); -+ ret |= reg16_write(client, 0x5009, ov490_s_gamma(ctrl->val, 0x9e)); -+ ret |= reg16_write(client, 0x500a, ov490_s_gamma(ctrl->val, 0xae)); -+ ret |= reg16_write(client, 0x500b, ov490_s_gamma(ctrl->val, 0xbc)); -+ ret |= reg16_write(client, 0x500c, ov490_s_gamma(ctrl->val, 0xcf)); -+ ret |= reg16_write(client, 0x500d, ov490_s_gamma(ctrl->val, 0xde)); -+ ret |= reg16_write(client, 0x500e, ov490_s_gamma(ctrl->val, 0xec)); -+ ret |= reg16_write(client, 0xFFFE, 0x80); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x00C0, 0xf9); -+ break; -+ case V4L2_CID_SHARPNESS: -+ ret = reg16_write(client, 0xFFFD, 0x80); -+ ret |= reg16_write(client, 0xFFFE, 0x19); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x5000, ctrl->val); -+ ret |= reg16_write(client, 0xFFFE, 0x80); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x00C0, 0xfb); -+ break; -+ case V4L2_CID_AUTOGAIN: -+ case V4L2_CID_GAIN: -+ case V4L2_CID_EXPOSURE: -+ if (ctrl->id == V4L2_CID_AUTOGAIN) -+ priv->autogain = ctrl->val; -+ if (ctrl->id == V4L2_CID_GAIN) -+ priv->gain = ctrl->val; -+ if (ctrl->id == V4L2_CID_EXPOSURE) -+ priv->exposure = ctrl->val; ++ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ++ return -EINVAL; ++ if (cp->extendedmode != 0) ++ return -EINVAL; + -+ ret = reg16_write(client, 0xFFFD, 0x80); -+ ret |= reg16_write(client, 0xFFFE, 0x19); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x5000, !priv->autogain); -+ ret |= reg16_write(client, 0x5001, priv->exposure >> 8); -+ ret |= reg16_write(client, 0x5002, priv->exposure & 0xff); -+ ret |= reg16_write(client, 0x5003, priv->exposure >> 8); -+ ret |= reg16_write(client, 0x5004, priv->exposure & 0xff); -+ ret |= reg16_write(client, 0x5005, priv->exposure >> 8); -+ ret |= reg16_write(client, 0x5006, priv->exposure & 0xff); -+ ret |= reg16_write(client, 0x5007, priv->gain >> 8); -+ ret |= reg16_write(client, 0x5008, priv->gain & 0xff); -+ ret |= reg16_write(client, 0x5009, priv->gain >> 8); -+ ret |= reg16_write(client, 0x500a, priv->gain & 0xff); -+ ret |= reg16_write(client, 0x500b, priv->gain >> 8); -+ ret |= reg16_write(client, 0x500c, priv->gain & 0xff); -+ ret |= reg16_write(client, 0xFFFE, 0x80); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x00C0, 0xea); -+ break; -+ case V4L2_CID_AUTO_WHITE_BALANCE: -+ case V4L2_CID_RED_BALANCE: -+ case V4L2_CID_BLUE_BALANCE: -+ if (ctrl->id == V4L2_CID_AUTO_WHITE_BALANCE) -+ priv->awb = ctrl->val; -+ if (ctrl->id == V4L2_CID_RED_BALANCE) { -+ priv->red = ctrl->val; -+ priv->red <<= 8; -+ priv->green_r = priv->red / 2; -+ } -+ if (ctrl->id == V4L2_CID_BLUE_BALANCE) { -+ priv->blue = ctrl->val; -+ priv->blue <<= 8; -+ priv->green_b = priv->blue / 2; ++ if (priv->fps_denominator != cp->timeperframe.denominator) { ++ switch (cp->timeperframe.denominator) { ++ case 5: ++ ret = ov10635_set_regs(client, ov10635_regs_5fps, ++ ARRAY_SIZE(ov10635_regs_5fps)); ++ break; ++ case 10: ++ ret = ov10635_set_regs(client, ov10635_regs_10fps, ++ ARRAY_SIZE(ov10635_regs_10fps)); ++ break; ++ case 15: ++ ret = ov10635_set_regs(client, ov10635_regs_15fps, ++ ARRAY_SIZE(ov10635_regs_15fps)); ++ break; ++ case 30: ++ ret = ov10635_set_regs(client, ov10635_regs_30fps, ++ ARRAY_SIZE(ov10635_regs_30fps)); ++ break; ++ default: ++ ret = -EINVAL; ++ goto out; + } + -+ ret = reg16_write(client, 0xFFFD, 0x80); -+ ret |= reg16_write(client, 0xFFFE, 0x19); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x5000, !priv->awb); -+ ret |= reg16_write(client, 0x5001, priv->red >> 8); -+ ret |= reg16_write(client, 0x5002, priv->red & 0xff); -+ ret |= reg16_write(client, 0x5003, priv->green_r >> 8); -+ ret |= reg16_write(client, 0x5004, priv->green_r & 0xff); -+ ret |= reg16_write(client, 0x5005, priv->green_b >> 8); -+ ret |= reg16_write(client, 0x5006, priv->green_b & 0xff); -+ ret |= reg16_write(client, 0x5007, priv->blue >> 8); -+ ret |= reg16_write(client, 0x5008, priv->blue & 0xff); -+ ret |= reg16_write(client, 0x5009, priv->red >> 8); -+ ret |= reg16_write(client, 0x500a, priv->red & 0xff); -+ ret |= reg16_write(client, 0x500b, priv->green_r >> 8); -+ ret |= reg16_write(client, 0x500c, priv->green_r & 0xff); -+ ret |= reg16_write(client, 0x500d, priv->green_b >> 8); -+ ret |= reg16_write(client, 0x500e, priv->green_b & 0xff); -+ ret |= reg16_write(client, 0x500f, priv->blue >> 8); -+ ret |= reg16_write(client, 0x5010, priv->blue & 0xff); -+ ret |= reg16_write(client, 0x5011, priv->red >> 8); -+ ret |= reg16_write(client, 0x5012, priv->red & 0xff); -+ ret |= reg16_write(client, 0x5013, priv->green_r >> 8); -+ ret |= reg16_write(client, 0x5014, priv->green_r & 0xff); -+ ret |= reg16_write(client, 0x5015, priv->green_b >> 8); -+ ret |= reg16_write(client, 0x5016, priv->green_b & 0xff); -+ ret |= reg16_write(client, 0x5017, priv->blue >> 8); -+ ret |= reg16_write(client, 0x5018, priv->blue & 0xff); -+ ret |= reg16_write(client, 0xFFFE, 0x80); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x00C0, 0xeb); -+ break; -+ case V4L2_CID_HFLIP: -+#if 1 -+ ret = reg16_write(client, 0xFFFD, 0x80); -+ ret |= reg16_write(client, 0xFFFE, 0x19); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x5000, ctrl->val); -+ ret |= reg16_write(client, 0x5001, 0x00); -+ ret |= reg16_write(client, 0xFFFE, 0x80); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x00C0, 0xdc); -+#else -+ ret = reg16_write(client, 0xFFFD, 0x80); -+ ret |= reg16_write(client, 0xFFFE, 0x19); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x5000, 0x01); // read 0x3128 -+ ret |= reg16_write(client, 0x5001, 0x31); -+ ret |= reg16_write(client, 0x5002, 0x28); -+ ret |= reg16_write(client, 0xFFFE, 0x80); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x00C0, 0xc1); -+ ret |= reg16_write(client, 0xFFFE, 0x19); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_read(client, 0x5000, &val); -+ val &= ~(0x1 << 0); -+ val |= (ctrl->val << 0); -+ ret |= reg16_write(client, 0xFFFE, 0x19); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x5000, 0x00); // write 0x3128 -+ ret |= reg16_write(client, 0x5001, 0x31); -+ ret |= reg16_write(client, 0x5002, 0x28); -+ ret |= reg16_write(client, 0x5003, val); -+ ret |= reg16_write(client, 0xFFFE, 0x80); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x00C0, 0xc1); ++ priv->fps_denominator = cp->timeperframe.denominator; ++ } ++ ++out: ++ return ret; ++} + -+ ret |= reg16_write(client, 0xFFFE, 0x19); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x5000, 0x01); // read 0x3291 -+ ret |= reg16_write(client, 0x5001, 0x32); -+ ret |= reg16_write(client, 0x5002, 0x91); -+ ret |= reg16_write(client, 0xFFFE, 0x80); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x00C0, 0xc1); -+ ret |= reg16_write(client, 0xFFFE, 0x19); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_read(client, 0x5000, &val); -+ val &= ~(0x1 << 1); -+ val |= (ctrl->val << 1); -+ ret |= reg16_write(client, 0xFFFE, 0x19); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x5000, 0x00); // write 0x3291 -+ ret |= reg16_write(client, 0x5001, 0x32); -+ ret |= reg16_write(client, 0x5002, 0x91); -+ ret |= reg16_write(client, 0x5003, val); -+ ret |= reg16_write(client, 0xFFFE, 0x80); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x00C0, 0xc1); ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++static int ov10635_g_register(struct v4l2_subdev *sd, ++ struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ int ret; ++ u8 val = 0; + -+ ret |= reg16_write(client, 0xFFFE, 0x19); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x5000, 0x01); // read 0x3090 -+ ret |= reg16_write(client, 0x5001, 0x30); -+ ret |= reg16_write(client, 0x5002, 0x90); -+ ret |= reg16_write(client, 0xFFFE, 0x80); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x00C0, 0xc1); -+ ret |= reg16_write(client, 0xFFFE, 0x19); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_read(client, 0x5000, &val); -+ val &= ~(0x1 << 2); -+ val |= (ctrl->val << 2); -+ ret |= reg16_write(client, 0xFFFE, 0x19); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x5000, 0x00); // write 0x3090 -+ ret |= reg16_write(client, 0x5001, 0x30); -+ ret |= reg16_write(client, 0x5002, 0x90); -+ ret |= reg16_write(client, 0x5003, val); -+ ret |= reg16_write(client, 0xFFFE, 0x80); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x00C0, 0xc1); -+#endif -+ break; -+ case V4L2_CID_VFLIP: -+#if 1 -+ ret = reg16_write(client, 0xFFFD, 0x80); -+ ret |= reg16_write(client, 0xFFFE, 0x19); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x5000, ctrl->val); -+ ret |= reg16_write(client, 0x5001, 0x01); -+ ret |= reg16_write(client, 0xFFFE, 0x80); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x00C0, 0xdc); -+#else -+ ret = reg16_write(client, 0xFFFD, 0x80); -+ ret |= reg16_write(client, 0xFFFE, 0x19); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x5000, 0x01); // read 0x3128 -+ ret |= reg16_write(client, 0x5001, 0x31); -+ ret |= reg16_write(client, 0x5002, 0x28); -+ ret |= reg16_write(client, 0xFFFE, 0x80); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x00C0, 0xc1); -+ ret |= reg16_write(client, 0xFFFE, 0x19); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_read(client, 0x5000, &val); -+ val &= ~(0x1 << 1); -+ val |= (ctrl->val << 1); -+ ret |= reg16_write(client, 0xFFFE, 0x19); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x5000, 0x00); // write 0x3128 -+ ret |= reg16_write(client, 0x5001, 0x31); -+ ret |= reg16_write(client, 0x5002, 0x28); -+ ret |= reg16_write(client, 0x5003, val); -+ ret |= reg16_write(client, 0xFFFE, 0x80); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x00C0, 0xc1); ++ ret = reg16_read(client, (u16)reg->reg, &val); ++ if (ret < 0) ++ return ret; + -+ ret |= reg16_write(client, 0xFFFE, 0x19); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x5000, 0x01); // read 0x3291 -+ ret |= reg16_write(client, 0x5001, 0x32); -+ ret |= reg16_write(client, 0x5002, 0x91); -+ ret |= reg16_write(client, 0xFFFE, 0x80); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x00C0, 0xc1); -+ ret |= reg16_write(client, 0xFFFE, 0x19); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_read(client, 0x5000, &val); -+ val &= ~(0x1 << 2); -+ val |= (ctrl->val << 2); -+ ret |= reg16_write(client, 0xFFFE, 0x19); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x5000, 0x00); // write 0x3291 -+ ret |= reg16_write(client, 0x5001, 0x32); -+ ret |= reg16_write(client, 0x5002, 0x91); -+ ret |= reg16_write(client, 0x5003, val); -+ ret |= reg16_write(client, 0xFFFE, 0x80); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x00C0, 0xc1); ++ reg->val = val; ++ reg->size = sizeof(u16); + -+ ret |= reg16_write(client, 0xFFFE, 0x19); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x5000, 0x01); // read 0x3090 -+ ret |= reg16_write(client, 0x5001, 0x30); -+ ret |= reg16_write(client, 0x5002, 0x90); -+ ret |= reg16_write(client, 0xFFFE, 0x80); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x00C0, 0xc1); -+ ret |= reg16_write(client, 0xFFFE, 0x19); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_read(client, 0x5000, &val); -+ val &= ~(0x1 << 3); -+ val |= (ctrl->val << 3); -+ ret |= reg16_write(client, 0xFFFE, 0x19); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x5000, 0x00); // write 0x3090 -+ ret |= reg16_write(client, 0x5001, 0x30); -+ ret |= reg16_write(client, 0x5002, 0x90); -+ ret |= reg16_write(client, 0x5003, val); -+ ret |= reg16_write(client, 0xFFFE, 0x80); -+ usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x00C0, 0xc1); ++ return 0; ++} ++ ++static int ov10635_s_register(struct v4l2_subdev *sd, ++ const struct v4l2_dbg_register *reg) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ ++ return reg16_write(client, (u16)reg->reg, (u8)reg->val); ++} ++#endif ++ ++static struct v4l2_subdev_core_ops ov10635_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = ov10635_g_register, ++ .s_register = ov10635_s_register, +#endif ++}; ++ ++static int ov10635_s_ctrl(struct v4l2_ctrl *ctrl) ++{ ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov10635_priv *priv = to_ov10635(client); ++ int ret = -EINVAL; ++ u8 val = 0; ++ ++ if (!priv->init_complete) ++ return 0; ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ /* AEC/AGC target */ ++ ret = reg16_write(client, 0xc46a, ctrl->val); ++ break; ++ case V4L2_CID_CONTRAST: ++ udelay(100); ++ ret = ov10635_set_regs(client, &ov10635_regs_contrast[ctrl->val][0], 18); ++ break; ++ case V4L2_CID_SATURATION: ++ ret = reg16_write(client, 0xc316, ctrl->val); ++ break; ++ case V4L2_CID_HUE: ++ /* CMX ? */ ++ ret = 0; ++ break; ++ case V4L2_CID_GAMMA: ++ ret = reg16_write(client, 0xc4be, ctrl->val >> 8); ++ ret |= reg16_write(client, 0xc4bf, ctrl->val & 0xff); ++ break; ++ case V4L2_CID_AUTOGAIN: ++ /* automatic gain/exposure */ ++ ret = reg16_write(client, 0x56d0, !ctrl->val); ++ break; ++ case V4L2_CID_GAIN: ++ /* manual gain */ ++ ret = reg16_write(client, 0x3504, 0); ++ ret |= reg16_write(client, 0x56d1, ctrl->val >> 8); ++ ret |= reg16_write(client, 0x56d2, ctrl->val & 0xff); ++ ret |= reg16_write(client, 0x3504, 1); /* validate gain */ ++ break; ++ case V4L2_CID_EXPOSURE: ++ /* manual exposure */ ++ ret = reg16_write(client, 0x3504, 0); ++ ret |= reg16_write(client, 0x56d5, ctrl->val >> 8); ++ ret |= reg16_write(client, 0x56d6, ctrl->val & 0xff); ++ ret |= reg16_write(client, 0x3504, 1); /* validate exposure */ ++ break; ++ case V4L2_CID_HFLIP: ++ ret = reg16_read(client, 0x381d, &val); ++ if (ret < 0) ++ goto out; ++ if (ctrl->val) ++ val |= 0x3; ++ else ++ val &= ~0x3; ++ ret = reg16_write(client, 0x381d, val); ++ break; ++ case V4L2_CID_VFLIP: ++ ret = reg16_read(client, 0x381c, &val); ++ if (ctrl->val) ++ val |= 0xc0; ++ else ++ val &= ~0xc0; ++ ret = reg16_write(client, 0x381c, val); + break; + case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: + ret = 0; + break; + } + ++out: + return ret; +} + -+static const struct v4l2_ctrl_ops ov490_ctrl_ops = { -+ .s_ctrl = ov490_s_ctrl, ++static const struct v4l2_ctrl_ops ov10635_ctrl_ops = { ++ .s_ctrl = ov10635_s_ctrl, +}; + -+static struct v4l2_subdev_video_ops ov490_video_ops = { -+ .s_stream = ov490_s_stream, -+ .g_mbus_config = ov490_g_mbus_config, ++static struct v4l2_subdev_video_ops ov10635_video_ops = { ++ .s_stream = ov10635_s_stream, ++ .g_mbus_config = ov10635_g_mbus_config, ++ .g_parm = ov10635_g_parm, ++ .s_parm = ov10635_s_parm, +}; + -+static const struct v4l2_subdev_pad_ops ov490_subdev_pad_ops = { -+ .get_edid = ov490_get_edid, -+ .enum_mbus_code = ov490_enum_mbus_code, -+ .get_selection = ov490_get_selection, -+ .set_selection = ov490_set_selection, -+ .get_fmt = ov490_get_fmt, -+ .set_fmt = ov490_set_fmt, ++static const struct v4l2_subdev_pad_ops ov10635_subdev_pad_ops = { ++ .get_edid = ov10635_get_edid, ++ .enum_mbus_code = ov10635_enum_mbus_code, ++ .get_selection = ov10635_get_selection, ++ .set_selection = ov10635_set_selection, ++ .get_fmt = ov10635_get_fmt, ++ .set_fmt = ov10635_set_fmt, +}; + -+static struct v4l2_subdev_ops ov490_subdev_ops = { -+ .core = &ov490_core_ops, -+ .video = &ov490_video_ops, -+ .pad = &ov490_subdev_pad_ops, ++static struct v4l2_subdev_ops ov10635_subdev_ops = { ++ .core = &ov10635_core_ops, ++ .video = &ov10635_video_ops, ++ .pad = &ov10635_subdev_pad_ops, +}; + -+static void ov490_otp_id_read(struct i2c_client *client) ++static void ov10635_otp_id_read(struct i2c_client *client) +{ -+ struct ov490_priv *priv = to_ov490(client); ++ struct ov10635_priv *priv = to_ov10635(client); + int i; -+ int otp_bank0_allzero = 1; + -+#if 0 -+ /* read camera id from ov490 OTP memory */ -+ reg16_write(client, 0xFFFD, 0x80); -+ reg16_write(client, 0xFFFE, 0x28); -+ usleep_range(100, 150); /* wait 100 us */ -+ reg16_write(client, 0xE084, 0x40); /* manual mode, bank#0 */ -+ reg16_write(client, 0xE081, 1); /* start OTP read */ ++ /* read camera id from OTP memory */ ++ reg16_write(client, 0x3d10, 1); + -+ usleep_range(25000, 26000); /* wait 25 ms */ ++ usleep_range(15000, 16000); /* wait 15ms */ + + for (i = 0; i < 6; i++) -+ reg16_read(client, 0xe000 + i + 4, &priv->id[i]); -+#else -+ /* read camera id from ov10640 OTP memory */ -+ ov490_ov10640_write(client, 0x349C, 1); -+ usleep_range(25000, 25500); /* wait 25 ms */ -+ -+ for (i = 0; i < 6; i++) { -+ /* first 6 bytes are equal on all ov10640 */ -+ priv->id[i] = ov490_ov10640_read(client, 0x349e + i + 6); -+ if (priv->id[i]) -+ otp_bank0_allzero = 0; -+ } -+ -+ if (otp_bank0_allzero) { -+ ov490_ov10640_write(client, 0x3495, 0x41); /* bank#1 */ -+ ov490_ov10640_write(client, 0x349C, 1); -+ usleep_range(25000, 25500); /* wait 25 ms */ -+ -+ for (i = 0; i < 6; i++) -+ priv->id[i] = ov490_ov10640_read(client, 0x34ae + i); -+ } -+#endif ++ reg16_read(client, 0x3d00 + i, &priv->id[i]); +} + -+static ssize_t ov490_otp_id_show(struct device *dev, -+ struct device_attribute *attr, char *buf) ++static ssize_t ov10635_otp_id_show(struct device *dev, ++ struct device_attribute *attr, char *buf) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev)); + struct i2c_client *client = v4l2_get_subdevdata(sd); -+ struct ov490_priv *priv = to_ov490(client); ++ struct ov10635_priv *priv = to_ov10635(client); + + return snprintf(buf, 32, "%02x:%02x:%02x:%02x:%02x:%02x\n", + priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); +} + -+static DEVICE_ATTR(otp_id_ov490, S_IRUGO, ov490_otp_id_show, NULL); ++static DEVICE_ATTR(otp_id_ov10635, S_IRUGO, ov10635_otp_id_show, NULL); + -+static int ov490_initialize(struct i2c_client *client) ++static int ov10635_initialize(struct i2c_client *client) +{ -+ struct ov490_priv *priv = to_ov490(client); -+ u8 val = 0; ++ struct ov10635_priv *priv = to_ov10635(client); + u8 pid = 0, ver = 0; -+ int ret = 0, timeout, retry_timeout = 3; -+ -+ if (priv->is_fixed_sensor) { -+ dev_info(&client->dev, "ov490/ov10640 fixed-sensor res %dx%d\n", priv->max_width, priv->max_height); -+ return 0; -+ } ++ int ret = 0; + -+ ov490_s_port(client, 1); ++ ov10635_s_port(client, 1); + + /* check and show product ID and manufacturer ID */ -+ reg16_write(client, 0xFFFD, 0x80); -+ reg16_write(client, 0xFFFE, 0x80); -+ usleep_range(100, 150); /* wait 100 us */ -+ reg16_read(client, OV490_PID, &pid); -+ reg16_read(client, OV490_VER, &ver); ++ reg16_read(client, OV10635_PID, &pid); ++ reg16_read(client, OV10635_VER, &ver); + -+ if (OV490_VERSION(pid, ver) != OV490_VERSION_REG) { ++ if (OV10635_VERSION(pid, ver) != OV10635_VERSION_REG) { + dev_dbg(&client->dev, "Product ID error %x:%x\n", pid, ver); + ret = -ENODEV; -+ goto err; -+ } -+ -+ if (unlikely(conf_link)) + goto out; -+ -+again: -+ /* Check if firmware booted by reading stream-on status */ -+ reg16_write(client, 0xFFFD, 0x80); -+ reg16_write(client, 0xFFFE, 0x29); -+ usleep_range(100, 150); /* wait 100 us */ -+ for (timeout = 300; timeout > 0; timeout--) { -+ reg16_read(client, 0xd000, &val); -+ if (val == 0x0c) -+ break; -+ mdelay(1); -+ } -+ -+ /* wait firmware apps started by reading OV10640 ID */ -+ for (;timeout > 0; timeout--) { -+ reg16_write(client, 0xFFFD, 0x80); -+ reg16_write(client, 0xFFFE, 0x19); -+ usleep_range(100, 150); /* wait 100 us */ -+ reg16_write(client, 0x5000, 0x01); -+ reg16_write(client, 0x5001, 0x30); -+ reg16_write(client, 0x5002, 0x0a); -+ reg16_write(client, 0xFFFE, 0x80); -+ usleep_range(100, 150); /* wait 100 us */ -+ reg16_write(client, 0xC0, 0xc1); -+ reg16_write(client, 0xFFFE, 0x19); -+ usleep_range(1000, 1500); /* wait 1 ms */ -+ reg16_read(client, 0x5000, &val); -+ if (val == 0xa6) -+ break; -+ mdelay(1); -+ } -+ -+ if (!timeout) { -+ dev_err(&client->dev, "Timeout firmware boot wait, retrying\n"); -+ /* reset OV10640 using RESETB pin controlled by OV490 GPIO0 */ -+ reg16_write(client, 0xFFFD, 0x80); -+ reg16_write(client, 0xFFFE, 0x80); -+ usleep_range(100, 150); /* wait 100 us */ -+ reg16_write(client, 0x0050, 0x01); -+ reg16_write(client, 0x0054, 0x01); -+ reg16_write(client, 0x0058, 0x00); -+ mdelay(10); -+ reg16_write(client, 0x0058, 0x01); -+ /* reset OV490 using RESETB pin controlled by serializer */ -+ ov490_reset(client); -+ if (retry_timeout--) -+ goto again; + } + -+ /* read resolution used by current firmware */ -+ reg16_write(client, 0xFFFD, 0x80); -+ reg16_write(client, 0xFFFE, 0x82); -+ usleep_range(100, 150); /* wait 100 us */ -+ reg16_read(client, OV490_ISP_HSIZE_HIGH, &val); -+ priv->max_width = val; -+ reg16_read(client, OV490_ISP_HSIZE_LOW, &val); -+ priv->max_width = (priv->max_width << 8) | val; -+ reg16_read(client, OV490_ISP_VSIZE_HIGH, &val); -+ priv->max_height = val; -+ reg16_read(client, OV490_ISP_VSIZE_LOW, &val); -+ priv->max_height = (priv->max_height << 8) | val; ++ /* s/w reset sensor */ ++ reg16_write(client, 0x103, 0x1); ++ udelay(100); + /* Program wizard registers */ -+ ov490_set_regs(client, ov490_regs_wizard, ARRAY_SIZE(ov490_regs_wizard)); ++ ov10635_set_regs(client, ov10635_regs_wizard, ARRAY_SIZE(ov10635_regs_wizard)); + /* Set DVP bit swap */ -+ reg16_write(client, 0xFFFD, 0x80); -+ reg16_write(client, 0xFFFE, 0x28); -+ usleep_range(100, 150); /* wait 100 us */ -+ reg16_write(client, 0x6009, priv->dvp_order << 4); ++ reg16_write(client, 0x4709, priv->dvp_order << 4); + /* Read OTP IDs */ -+ ov490_otp_id_read(client); ++ ov10635_otp_id_read(client); + ++ dev_info(&client->dev, "ov10635 Product ID %x Manufacturer ID %x OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n", ++ pid, ver, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); +out: -+ dev_info(&client->dev, "ov490/ov10640 PID %x%x, res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n", -+ pid, ver, priv->max_width, priv->max_height, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); -+err: -+ ov490_s_port(client, 0); ++ ov10635_s_port(client, 0); + + return ret; +} + -+static int ov490_parse_dt(struct device_node *np, struct ov490_priv *priv) ++static int ov10635_parse_dt(struct device_node *np, struct ov10635_priv *priv) +{ + struct i2c_client *client = v4l2_get_subdevdata(&priv->sd); + int i; -+ const char *fixed_sensor; + struct device_node *endpoint = NULL, *rendpoint = NULL; + int tmp_addr = 0; + @@ -5544,17 +3653,8 @@ index 0000000..f1e34a3 + + if (!of_property_read_u32(rendpoint, "max9271-addr", &priv->max9271_addr) && + !of_property_read_u32(rendpoint->parent->parent, "reg", &priv->max9286_addr) && -+ !kstrtouint(strrchr(rendpoint->full_name, '@') + 1, 0, &priv->port)) { -+ if (of_property_read_u32(rendpoint->parent->parent, "maxim,resetb-gpio", &priv->gpio_resetb)) { -+ priv->gpio_resetb = -1; -+ } else { -+ if (of_property_read_bool(rendpoint->parent->parent, "maxim,resetb-active-high")) -+ priv->active_low_resetb = false; -+ else -+ priv->active_low_resetb = true; -+ } ++ !kstrtouint(strrchr(rendpoint->full_name, '@') + 1, 0, &priv->port)) + break; -+ } + + if (!of_property_read_u32(rendpoint, "ti9x3-addr", &priv->ti9x3_addr) && + !of_property_match_string(rendpoint->parent->parent, "compatible", "ti,ti964-ti9x3") && @@ -5570,11 +3670,11 @@ index 0000000..f1e34a3 + } + + if (!priv->max9286_addr && !priv->ti964_addr && !priv->ti954_addr) { -+ dev_err(&client->dev, "deserializer does not present for OV490\n"); ++ dev_err(&client->dev, "deserializer does not present for OV10635\n"); + return -EINVAL; + } + -+ ov490_s_port(client, 1); ++ ov10635_s_port(client, 1); + + /* setup I2C translator address */ + tmp_addr = client->addr; @@ -5582,106 +3682,79 @@ index 0000000..f1e34a3 + client->addr = priv->max9271_addr; /* Serializer I2C address */ + + reg8_write(client, 0x09, tmp_addr << 1); /* Sensor translated I2C address */ -+ reg8_write(client, 0x0A, OV490_I2C_ADDR << 1); /* Sensor native I2C address */ ++ reg8_write(client, 0x0A, OV10635_I2C_ADDR << 1); /* Sensor native I2C address */ + usleep_range(2000, 2500); /* wait 2ms */ + }; ++ + if (priv->ti964_addr) { + client->addr = priv->ti964_addr; /* Deserializer I2C address */ + + reg8_write(client, 0x4c, (priv->port << 4) | (1 << priv->port)); /* Select RX port number */ + usleep_range(2000, 2500); /* wait 2ms */ + reg8_write(client, 0x65, tmp_addr << 1); /* Sensor translated I2C address */ -+ reg8_write(client, 0x5d, OV490_I2C_ADDR << 1); /* Sensor native I2C address */ ++ reg8_write(client, 0x5d, OV10635_I2C_ADDR << 1); /* Sensor native I2C address */ + -+ reg8_write(client, 0x6e, 0x9a); /* GPIO0 - fsin, GPIO1 - resetb */ ++ reg8_write(client, 0x6e, 0xa9); /* GPIO0 - resetb, GPIO1 - fsin */ + } ++ + if (priv->ti954_addr) { + client->addr = priv->ti954_addr; /* Deserializer I2C address */ + + reg8_write(client, 0x4c, (priv->port << 4) | (1 << priv->port)); /* Select RX port number */ + usleep_range(2000, 2500); /* wait 2ms */ + reg8_write(client, 0x65, tmp_addr << 1); /* Sensor translated I2C address */ -+ reg8_write(client, 0x5d, OV490_I2C_ADDR << 1); /* Sensor native I2C address */ ++ reg8_write(client, 0x5d, OV10635_I2C_ADDR << 1); /* Sensor native I2C address */ + -+ reg8_write(client, 0x6e, 0x9a); /* GPIO0 - fsin, GPIO1 - resetb */ ++ reg8_write(client, 0x6e, 0xa9); /* GPIO0 - resetb, GPIO1 - fsin */ + } + client->addr = tmp_addr; -+ -+ if (!of_property_read_string(np, "maxim,fixed-sensor", &fixed_sensor) && -+ strcmp(fixed_sensor, "ov490") == 0) { -+ if (of_property_read_u32(np, "maxim,width", &priv->max_width)) -+ priv->max_width = 1280; -+ -+ if (of_property_read_u32(np, "maxim,height", &priv->max_height)) -+ priv->max_height = 966; -+ -+ priv->is_fixed_sensor = true; -+ } -+ -+ /* module params override dts */ -+ if (dvp_order) -+ priv->dvp_order = dvp_order; -+ if (max_width && max_height) { -+ priv->max_width = max_width; -+ priv->max_height = max_height; -+ priv->is_fixed_sensor = true; -+ } -+ -+ return 0; -+} -+ -+static int ov490_probe(struct i2c_client *client, -+ const struct i2c_device_id *did) -+{ -+ struct ov490_priv *priv; -+ struct v4l2_ctrl *ctrl; -+ int ret; -+ -+ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ v4l2_i2c_subdev_init(&priv->sd, client, &ov490_subdev_ops); -+ priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; -+ -+ priv->exposure = 0x100; -+ priv->gain = 0x100; -+ priv->autogain = 1; -+ priv->red = 0x400; -+ priv->blue = 0x400; -+ priv->green_r = priv->red / 2; -+ priv->green_b = priv->blue / 2; -+ priv->awb = 1; -+ v4l2_ctrl_handler_init(&priv->hdl, 4); -+ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, -+ V4L2_CID_BRIGHTNESS, 0, 16, 1, 7); -+ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, -+ V4L2_CID_CONTRAST, 0, 16, 1, 7); -+ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, -+ V4L2_CID_SATURATION, 0, 7, 1, 2); -+ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, -+ V4L2_CID_HUE, 0, 23, 1, 12); -+ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, -+ V4L2_CID_GAMMA, -128, 128, 1, 0); -+ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, -+ V4L2_CID_SHARPNESS, 0, 10, 1, 3); -+ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, -+ V4L2_CID_AUTOGAIN, 0, 1, 1, priv->autogain); -+ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, -+ V4L2_CID_GAIN, 0, 0xffff, 1, priv->gain); -+ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, -+ V4L2_CID_EXPOSURE, 0, 0xffff, 1, priv->exposure); -+ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, -+ V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, priv->autogain); -+ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, -+ V4L2_CID_RED_BALANCE, 2, 0xf, 1, priv->red >> 8); -+ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, -+ V4L2_CID_BLUE_BALANCE, 2, 0xf, 1, priv->blue >> 8); -+ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, -+ V4L2_CID_HFLIP, 0, 1, 1, 1); -+ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, ++ ++ udelay(100); ++ ++ return 0; ++} ++ ++static int ov10635_probe(struct i2c_client *client, ++ const struct i2c_device_id *did) ++{ ++ struct ov10635_priv *priv; ++ struct v4l2_ctrl *ctrl; ++ int ret; ++ ++ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ ++ v4l2_i2c_subdev_init(&priv->sd, client, &ov10635_subdev_ops); ++ priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; ++ priv->rect.left = 0; ++ priv->rect.top = 0; ++ priv->rect.width = OV10635_MAX_WIDTH; ++ priv->rect.height = OV10635_MAX_HEIGHT; ++ priv->fps_denominator = 30; ++ ++ v4l2_ctrl_handler_init(&priv->hdl, 4); ++ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 0xff, 1, 0x30); ++ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 4, 1, 2); ++ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops, ++ V4L2_CID_SATURATION, 0, 0xff, 1, 0xff); ++ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops, ++ V4L2_CID_HUE, 0, 255, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops, ++ V4L2_CID_GAMMA, 0, 0xffff, 1, 0x233); ++ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops, ++ V4L2_CID_AUTOGAIN, 0, 1, 1, 1); ++ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops, ++ V4L2_CID_GAIN, 0, 0x3ff, 1, 0x10); ++ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops, ++ V4L2_CID_EXPOSURE, 0, 0xffff, 1, 0x80); ++ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); -+ ctrl = v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, ++ ctrl = v4l2_ctrl_new_std(&priv->hdl, &ov10635_ctrl_ops, + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 9); + if (ctrl) + ctrl->flags &= ~V4L2_CTRL_FLAG_READ_ONLY; @@ -5699,93 +3772,1293 @@ index 0000000..f1e34a3 + if (ret < 0) + goto cleanup; + -+ ret = ov490_parse_dt(client->dev.of_node, priv); ++ ret = ov10635_parse_dt(client->dev.of_node, priv); ++ if (ret) ++ goto cleanup; ++ ++ ret = ov10635_initialize(client); ++ if (ret < 0) ++ goto cleanup; ++ ++ ret = v4l2_async_register_subdev(&priv->sd); + if (ret) + goto cleanup; + -+ ret = ov490_initialize(client); -+ if (ret < 0) -+ goto cleanup; ++ if (device_create_file(&client->dev, &dev_attr_otp_id_ov10635) != 0) { ++ dev_err(&client->dev, "sysfs otp_id entry creation failed\n"); ++ goto cleanup; ++ } ++ ++ priv->init_complete = 1; ++ ++ return 0; ++ ++cleanup: ++ media_entity_cleanup(&priv->sd.entity); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ v4l2_device_unregister_subdev(&priv->sd); ++#ifdef CONFIG_SOC_CAMERA_OV10635 ++ v4l_err(client, "failed to probe @ 0x%02x (%s)\n", ++ client->addr, client->adapter->name); ++#endif ++ return ret; ++} ++ ++static int ov10635_remove(struct i2c_client *client) ++{ ++ struct ov10635_priv *priv = i2c_get_clientdata(client); ++ ++ device_remove_file(&client->dev, &dev_attr_otp_id_ov10635); ++ v4l2_async_unregister_subdev(&priv->sd); ++ media_entity_cleanup(&priv->sd.entity); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ v4l2_device_unregister_subdev(&priv->sd); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_SOC_CAMERA_OV10635 ++static const struct i2c_device_id ov10635_id[] = { ++ { "ov10635", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, ov10635_id); ++ ++static const struct of_device_id ov10635_of_ids[] = { ++ { .compatible = "ovti,ov10635", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, ov10635_of_ids); ++ ++static struct i2c_driver ov10635_i2c_driver = { ++ .driver = { ++ .name = "ov10635", ++ .of_match_table = ov10635_of_ids, ++ }, ++ .probe = ov10635_probe, ++ .remove = ov10635_remove, ++ .id_table = ov10635_id, ++}; ++ ++module_i2c_driver(ov10635_i2c_driver); ++ ++MODULE_DESCRIPTION("SoC Camera driver for OV10635"); ++MODULE_AUTHOR("Vladimir Barinov"); ++MODULE_LICENSE("GPL"); ++#endif +diff --git a/drivers/media/i2c/soc_camera/ov10635.h b/drivers/media/i2c/soc_camera/ov10635.h +new file mode 100644 +index 0000000..a0e510d +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/ov10635.h +@@ -0,0 +1,1139 @@ ++/* ++ * OmniVision ov10635 sensor camera wizard 1280x800@30/UYVY/BT601/8bit ++ * ++ * Copyright (C) 2015-2017 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++//#define OV10635_DISPLAY_PATTERN ++ ++#define OV10635_SENSOR_WIDTH 1312 ++#define OV10635_SENSOR_HEIGHT 814 ++ ++#define OV10635_MAX_WIDTH 1280 ++#define OV10635_MAX_HEIGHT 800 ++ ++//#define OV10635_PCLK_96MHZ ++#define OV10635_PCLK_88MHZ ++ ++#if defined(OV10635_PCLK_96MHZ) ++/* VTS=PCLK/FPS/HTS/2 (=96MHz/30/1600/2) */ ++ #define OV10635_HTS 1600 ++ #define OV10635_VTS 1000 /* fps=30 */ ++#elif defined(OV10635_PCLK_88MHZ) ++/* VTS=PCLK/FPS/HTS/2 (=88MHz/1572/30/2) */ ++ #define OV10635_HTS 1572 ++ #define OV10635_VTS 933 /* fps=29.9998 */ ++#else ++ #error PCLK not defined ++#endif ++ ++struct ov10635_reg { ++ u16 reg; ++ u8 val; ++}; ++ ++static const struct ov10635_reg ov10635_regs_wizard[] = { ++//{0x0103, 0x01}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x300C, 0x61}, ++{0x301B, 0xFF}, ++{0x301C, 0xFF}, ++{0x301A, 0xFF}, ++{0x3011, 0x42}, ++{0x6900, 0x0C}, ++{0x6901, 0x19}, ++{0x3503, 0x10}, ++{0x3025, 0x03}, ++#if defined(OV10635_PCLK_96MHZ) ++{0x3003, 0x20}, ++{0x3004, 0x21}, ++#elif defined(OV10635_PCLK_88MHZ) ++{0x3003, 0x16}, ++{0x3004, 0x30}, ++#endif ++{0x3005, 0x40}, ++{0x3006, 0x91}, ++{0x3600, 0x74}, ++{0x3601, 0x2B}, ++{0x3612, 0x00}, ++{0x3611, 0x67}, ++{0x3633, 0xCA}, ++{0x3602, 0xAF}, ++{0x3603, 0x04}, ++{0x3630, 0x28}, ++{0x3631, 0x16}, ++{0x3714, 0x10}, ++{0x371D, 0x01}, ++{0x4300, 0x3A}, ++{0x3007, 0x01}, ++{0x3024, 0x03}, ++{0x3020, 0x0A}, ++{0x3702, 0x0D}, ++{0x3703, 0x20}, ++{0x3704, 0x15}, ++{0x3709, 0xA8}, ++{0x370C, 0xC7}, ++{0x370D, 0x80}, ++{0x3712, 0x00}, ++{0x3713, 0x20}, ++{0x3715, 0x04}, ++{0x381D, 0x40}, ++{0x381C, 0x00}, ++{0x3822, 0x50}, ++{0x3824, 0x10}, ++{0x3815, 0x8C}, ++{0x3804, 0x05}, ++{0x3805, 0x1F}, ++{0x3800, 0x00}, ++{0x3801, 0x00}, ++{0x3806, 0x03}, ++{0x3807, 0x28}, ++{0x3802, 0x00}, ++{0x3803, 0x07}, ++{0x3808, 0x05}, ++{0x3809, 0x00}, ++{0x380A, 0x03}, ++{0x380B, 0x20}, ++{0x380C, OV10635_HTS >> 8}, ++{0x380D, OV10635_HTS & 0xff}, ++{0x380E, OV10635_VTS >> 8}, ++{0x380F, OV10635_VTS & 0xff}, ++{0x3813, 0x02}, ++{0x3811, 0x08}, ++{0x381F, 0x0C}, ++{0x3819, 0x04}, ++{0x3804, 0x01}, ++{0x3805, 0x00}, ++{0x3828, 0x03}, ++{0x3829, 0x10}, ++{0x382A, 0x10}, ++{0x3621, 0x63}, ++{0x5005, 0x08}, ++{0x56D5, 0x00}, ++{0x56D6, 0x80}, ++{0x56D7, 0x00}, ++{0x56D8, 0x00}, ++{0x56D9, 0x00}, ++{0x56DA, 0x80}, ++{0x56DB, 0x00}, ++{0x56DC, 0x00}, ++{0x56E8, 0x00}, ++{0x56E9, 0x7F}, ++{0x56EA, 0x00}, ++{0x56EB, 0x7F}, ++{0x5100, 0x00}, ++{0x5101, 0x80}, ++{0x5102, 0x00}, ++{0x5103, 0x80}, ++{0x5104, 0x00}, ++{0x5105, 0x80}, ++{0x5106, 0x00}, ++{0x5107, 0x80}, ++{0x5108, 0x00}, ++{0x5109, 0x00}, ++{0x510A, 0x00}, ++{0x510B, 0x00}, ++{0x510C, 0x00}, ++{0x510D, 0x00}, ++{0x510E, 0x00}, ++{0x510F, 0x00}, ++{0x5110, 0x00}, ++{0x5111, 0x80}, ++{0x5112, 0x00}, ++{0x5113, 0x80}, ++{0x5114, 0x00}, ++{0x5115, 0x80}, ++{0x5116, 0x00}, ++{0x5117, 0x80}, ++{0x5118, 0x00}, ++{0x5119, 0x00}, ++{0x511A, 0x00}, ++{0x511B, 0x00}, ++{0x511C, 0x00}, ++{0x511D, 0x00}, ++{0x511E, 0x00}, ++{0x511F, 0x00}, ++{0x56D0, 0x00}, ++{0x5006, 0x04}, ++{0x5608, 0x05}, ++{0x52D7, 0x06}, ++{0x528D, 0x08}, ++{0x5293, 0x12}, ++{0x52D3, 0x12}, ++{0x5288, 0x06}, ++{0x5289, 0x20}, ++{0x52C8, 0x06}, ++{0x52C9, 0x20}, ++{0x52CD, 0x04}, ++{0x5381, 0x00}, ++{0x5382, 0xFF}, ++{0x5589, 0x76}, ++{0x558A, 0x47}, ++{0x558B, 0xEF}, ++{0x558C, 0xC9}, ++{0x558D, 0x49}, ++{0x558E, 0x30}, ++{0x558F, 0x67}, ++{0x5590, 0x3F}, ++{0x5591, 0xF0}, ++{0x5592, 0x10}, ++{0x55A2, 0x6D}, ++{0x55A3, 0x55}, ++{0x55A4, 0xC3}, ++{0x55A5, 0xB5}, ++{0x55A6, 0x43}, ++{0x55A7, 0x38}, ++{0x55A8, 0x5F}, ++{0x55A9, 0x4B}, ++{0x55AA, 0xF0}, ++{0x55AB, 0x10}, ++{0x5581, 0x52}, ++{0x5300, 0x01}, ++{0x5301, 0x00}, ++{0x5302, 0x00}, ++{0x5303, 0x0E}, ++{0x5304, 0x00}, ++{0x5305, 0x0E}, ++{0x5306, 0x00}, ++{0x5307, 0x36}, ++{0x5308, 0x00}, ++{0x5309, 0xD9}, ++{0x530A, 0x00}, ++{0x530B, 0x0F}, ++{0x530C, 0x00}, ++{0x530D, 0x2C}, ++{0x530E, 0x00}, ++{0x530F, 0x59}, ++{0x5310, 0x00}, ++{0x5311, 0x7B}, ++{0x5312, 0x00}, ++{0x5313, 0x22}, ++{0x5314, 0x00}, ++{0x5315, 0xD5}, ++{0x5316, 0x00}, ++{0x5317, 0x13}, ++{0x5318, 0x00}, ++{0x5319, 0x18}, ++{0x531A, 0x00}, ++{0x531B, 0x26}, ++{0x531C, 0x00}, ++{0x531D, 0xDC}, ++{0x531E, 0x00}, ++{0x531F, 0x02}, ++{0x5320, 0x00}, ++{0x5321, 0x24}, ++{0x5322, 0x00}, ++{0x5323, 0x56}, ++{0x5324, 0x00}, ++{0x5325, 0x85}, ++{0x5326, 0x00}, ++{0x5327, 0x20}, ++{0x5609, 0x01}, ++{0x560A, 0x40}, ++{0x560B, 0x01}, ++{0x560C, 0x40}, ++{0x560D, 0x00}, ++{0x560E, 0xFA}, ++{0x560F, 0x00}, ++{0x5610, 0xFA}, ++{0x5611, 0x02}, ++{0x5612, 0x80}, ++{0x5613, 0x02}, ++{0x5614, 0x80}, ++{0x5615, 0x01}, ++{0x5616, 0x2C}, ++{0x5617, 0x01}, ++{0x5618, 0x2C}, ++{0x563B, 0x01}, ++{0x563C, 0x01}, ++{0x563D, 0x01}, ++{0x563E, 0x01}, ++{0x563F, 0x03}, ++{0x5640, 0x03}, ++{0x5641, 0x03}, ++{0x5642, 0x05}, ++{0x5643, 0x09}, ++{0x5644, 0x05}, ++{0x5645, 0x05}, ++{0x5646, 0x05}, ++{0x5647, 0x05}, ++{0x5651, 0x00}, ++{0x5652, 0x80}, ++{0x521A, 0x01}, ++{0x521B, 0x03}, ++{0x521C, 0x06}, ++{0x521D, 0x0A}, ++{0x521E, 0x0E}, ++{0x521F, 0x12}, ++{0x5220, 0x16}, ++{0x5223, 0x02}, ++{0x5225, 0x04}, ++{0x5227, 0x08}, ++{0x5229, 0x0C}, ++{0x522B, 0x12}, ++{0x522D, 0x18}, ++{0x522F, 0x1E}, ++{0x5241, 0x04}, ++{0x5242, 0x01}, ++{0x5243, 0x03}, ++{0x5244, 0x06}, ++{0x5245, 0x0A}, ++{0x5246, 0x0E}, ++{0x5247, 0x12}, ++{0x5248, 0x16}, ++{0x524A, 0x03}, ++{0x524C, 0x04}, ++{0x524E, 0x08}, ++{0x5250, 0x0C}, ++{0x5252, 0x12}, ++{0x5254, 0x18}, ++{0x5256, 0x1E}, ++{0x4606, (2*OV10635_HTS) >> 8}, /* fifo_line_length = 2*hts */ ++{0x4607, (2*OV10635_HTS) & 0xff}, ++{0x460a, (2*(OV10635_HTS-OV10635_MAX_WIDTH)) >> 8}, /* fifo_hsync_start = 2*(hts - xres) */ ++{0x460b, (2*(OV10635_HTS-OV10635_MAX_WIDTH)) & 0xff }, ++{0x460C, 0x00}, ++{0x4620, 0x0E}, ++#if 0 ++{0x4700, 0x02}, // BT656: mode is acceptable but artefact lines on left/bottom due to BT656 SAV/EAV are parsed as image data ++#else ++{0x4700, 0x04}, // BT601: 0x08 is also accaptable as HS/VS mode ++#endif ++{0x4701, 0x00}, ++{0x4702, 0x01}, ++{0x4004, 0x04}, ++{0x4005, 0x18}, ++{0x4001, 0x06}, ++{0x4050, 0x22}, ++{0x4051, 0x24}, ++{0x4052, 0x02}, ++{0x4057, 0x9C}, ++{0x405A, 0x00}, ++{0x4202, 0x02}, ++{0x3023, 0x10}, ++{0x0100, 0x01}, ++{0x0100, 0x01}, ++{0x6F10, 0x07}, ++{0x6F11, 0x82}, ++{0x6F12, 0x04}, ++{0x6F13, 0x00}, ++{0xD000, 0x19}, ++{0xD001, 0xA0}, ++{0xD002, 0x00}, ++{0xD003, 0x01}, ++{0xD004, 0xA9}, ++{0xD005, 0xAD}, ++{0xD006, 0x10}, ++{0xD007, 0x40}, ++{0xD008, 0x44}, ++{0xD009, 0x00}, ++{0xD00A, 0x68}, ++{0xD00B, 0x00}, ++{0xD00C, 0x15}, ++{0xD00D, 0x00}, ++{0xD00E, 0x00}, ++{0xD00F, 0x00}, ++{0xD040, 0x9C}, ++{0xD041, 0x21}, ++{0xD042, 0xFF}, ++{0xD043, 0xF8}, ++{0xD044, 0xD4}, ++{0xD045, 0x01}, ++{0xD046, 0x48}, ++{0xD047, 0x00}, ++{0xD048, 0xD4}, ++{0xD049, 0x01}, ++{0xD04A, 0x50}, ++{0xD04B, 0x04}, ++{0xD04C, 0x18}, ++{0xD04D, 0x60}, ++{0xD04E, 0x00}, ++{0xD04F, 0x01}, ++{0xD050, 0xA8}, ++{0xD051, 0x63}, ++{0xD052, 0x02}, ++{0xD053, 0xA4}, ++{0xD054, 0x85}, ++{0xD055, 0x43}, ++{0xD056, 0x00}, ++{0xD057, 0x00}, ++{0xD058, 0x18}, ++{0xD059, 0x60}, ++{0xD05A, 0x00}, ++{0xD05B, 0x01}, ++{0xD05C, 0xA8}, ++{0xD05D, 0x63}, ++{0xD05E, 0x03}, ++{0xD05F, 0xF0}, ++{0xD060, 0x98}, ++{0xD061, 0xA3}, ++{0xD062, 0x00}, ++{0xD063, 0x00}, ++{0xD064, 0x8C}, ++{0xD065, 0x6A}, ++{0xD066, 0x00}, ++{0xD067, 0x6E}, ++{0xD068, 0xE5}, ++{0xD069, 0x85}, ++{0xD06A, 0x18}, ++{0xD06B, 0x00}, ++{0xD06C, 0x10}, ++{0xD06D, 0x00}, ++{0xD06E, 0x00}, ++{0xD06F, 0x10}, ++{0xD070, 0x9C}, ++{0xD071, 0x80}, ++{0xD072, 0x00}, ++{0xD073, 0x03}, ++{0xD074, 0x18}, ++{0xD075, 0x60}, ++{0xD076, 0x00}, ++{0xD077, 0x01}, ++{0xD078, 0xA8}, ++{0xD079, 0x63}, ++{0xD07A, 0x07}, ++{0xD07B, 0x80}, ++{0xD07C, 0x07}, ++{0xD07D, 0xFF}, ++{0xD07E, 0xF9}, ++{0xD07F, 0x03}, ++{0xD080, 0x8C}, ++{0xD081, 0x63}, ++{0xD082, 0x00}, ++{0xD083, 0x00}, ++{0xD084, 0xA5}, ++{0xD085, 0x6B}, ++{0xD086, 0x00}, ++{0xD087, 0xFF}, ++{0xD088, 0x18}, ++{0xD089, 0x80}, ++{0xD08A, 0x00}, ++{0xD08B, 0x01}, ++{0xD08C, 0xA8}, ++{0xD08D, 0x84}, ++{0xD08E, 0x01}, ++{0xD08F, 0x04}, ++{0xD090, 0xE1}, ++{0xD091, 0x6B}, ++{0xD092, 0x58}, ++{0xD093, 0x00}, ++{0xD094, 0x94}, ++{0xD095, 0x6A}, ++{0xD096, 0x00}, ++{0xD097, 0x70}, ++{0xD098, 0xE1}, ++{0xD099, 0x6B}, ++{0xD09A, 0x20}, ++{0xD09B, 0x00}, ++{0xD09C, 0x95}, ++{0xD09D, 0x6B}, ++{0xD09E, 0x00}, ++{0xD09F, 0x00}, ++{0xD0A0, 0xE4}, ++{0xD0A1, 0x8B}, ++{0xD0A2, 0x18}, ++{0xD0A3, 0x00}, ++{0xD0A4, 0x0C}, ++{0xD0A5, 0x00}, ++{0xD0A6, 0x00}, ++{0xD0A7, 0x23}, ++{0xD0A8, 0x15}, ++{0xD0A9, 0x00}, ++{0xD0AA, 0x00}, ++{0xD0AB, 0x00}, ++{0xD0AC, 0x18}, ++{0xD0AD, 0x60}, ++{0xD0AE, 0x80}, ++{0xD0AF, 0x06}, ++{0xD0B0, 0xA8}, ++{0xD0B1, 0x83}, ++{0xD0B2, 0x40}, ++{0xD0B3, 0x08}, ++{0xD0B4, 0xA8}, ++{0xD0B5, 0xE3}, ++{0xD0B6, 0x38}, ++{0xD0B7, 0x2A}, ++{0xD0B8, 0xA8}, ++{0xD0B9, 0xC3}, ++{0xD0BA, 0x40}, ++{0xD0BB, 0x09}, ++{0xD0BC, 0xA8}, ++{0xD0BD, 0xA3}, ++{0xD0BE, 0x38}, ++{0xD0BF, 0x29}, ++{0xD0C0, 0x8C}, ++{0xD0C1, 0x65}, ++{0xD0C2, 0x00}, ++{0xD0C3, 0x00}, ++{0xD0C4, 0xD8}, ++{0xD0C5, 0x04}, ++{0xD0C6, 0x18}, ++{0xD0C7, 0x00}, ++{0xD0C8, 0x8C}, ++{0xD0C9, 0x67}, ++{0xD0CA, 0x00}, ++{0xD0CB, 0x00}, ++{0xD0CC, 0xD8}, ++{0xD0CD, 0x06}, ++{0xD0CE, 0x18}, ++{0xD0CF, 0x00}, ++{0xD0D0, 0x18}, ++{0xD0D1, 0x60}, ++{0xD0D2, 0x80}, ++{0xD0D3, 0x06}, ++{0xD0D4, 0xA8}, ++{0xD0D5, 0xE3}, ++{0xD0D6, 0x67}, ++{0xD0D7, 0x02}, ++{0xD0D8, 0xA9}, ++{0xD0D9, 0x03}, ++{0xD0DA, 0x67}, ++{0xD0DB, 0x03}, ++{0xD0DC, 0xA8}, ++{0xD0DD, 0xC3}, ++{0xD0DE, 0x3D}, ++{0xD0DF, 0x05}, ++{0xD0E0, 0x8C}, ++{0xD0E1, 0x66}, ++{0xD0E2, 0x00}, ++{0xD0E3, 0x00}, ++{0xD0E4, 0xB8}, ++{0xD0E5, 0x63}, ++{0xD0E6, 0x00}, ++{0xD0E7, 0x18}, ++{0xD0E8, 0xB8}, ++{0xD0E9, 0x63}, ++{0xD0EA, 0x00}, ++{0xD0EB, 0x98}, ++{0xD0EC, 0xBC}, ++{0xD0ED, 0x03}, ++{0xD0EE, 0x00}, ++{0xD0EF, 0x00}, ++{0xD0F0, 0x10}, ++{0xD0F1, 0x00}, ++{0xD0F2, 0x00}, ++{0xD0F3, 0x16}, ++{0xD0F4, 0xB8}, ++{0xD0F5, 0x83}, ++{0xD0F6, 0x00}, ++{0xD0F7, 0x19}, ++{0xD0F8, 0x8C}, ++{0xD0F9, 0x67}, ++{0xD0FA, 0x00}, ++{0xD0FB, 0x00}, ++{0xD0FC, 0xB8}, ++{0xD0FD, 0xA4}, ++{0xD0FE, 0x00}, ++{0xD0FF, 0x98}, ++{0xD100, 0xB8}, ++{0xD101, 0x83}, ++{0xD102, 0x00}, ++{0xD103, 0x08}, ++{0xD104, 0x8C}, ++{0xD105, 0x68}, ++{0xD106, 0x00}, ++{0xD107, 0x00}, ++{0xD108, 0xE0}, ++{0xD109, 0x63}, ++{0xD10A, 0x20}, ++{0xD10B, 0x04}, ++{0xD10C, 0xE0}, ++{0xD10D, 0x65}, ++{0xD10E, 0x18}, ++{0xD10F, 0x00}, ++{0xD110, 0xA4}, ++{0xD111, 0x83}, ++{0xD112, 0xFF}, ++{0xD113, 0xFF}, ++{0xD114, 0xB8}, ++{0xD115, 0x64}, ++{0xD116, 0x00}, ++{0xD117, 0x48}, ++{0xD118, 0xD8}, ++{0xD119, 0x07}, ++{0xD11A, 0x18}, ++{0xD11B, 0x00}, ++{0xD11C, 0xD8}, ++{0xD11D, 0x08}, ++{0xD11E, 0x20}, ++{0xD11F, 0x00}, ++{0xD120, 0x9C}, ++{0xD121, 0x60}, ++{0xD122, 0x00}, ++{0xD123, 0x00}, ++{0xD124, 0xD8}, ++{0xD125, 0x06}, ++{0xD126, 0x18}, ++{0xD127, 0x00}, ++{0xD128, 0x00}, ++{0xD129, 0x00}, ++{0xD12A, 0x00}, ++{0xD12B, 0x08}, ++{0xD12C, 0x15}, ++{0xD12D, 0x00}, ++{0xD12E, 0x00}, ++{0xD12F, 0x00}, ++{0xD130, 0x8C}, ++{0xD131, 0x6A}, ++{0xD132, 0x00}, ++{0xD133, 0x76}, ++{0xD134, 0xBC}, ++{0xD135, 0x23}, ++{0xD136, 0x00}, ++{0xD137, 0x00}, ++{0xD138, 0x13}, ++{0xD139, 0xFF}, ++{0xD13A, 0xFF}, ++{0xD13B, 0xE6}, ++{0xD13C, 0x18}, ++{0xD13D, 0x60}, ++{0xD13E, 0x80}, ++{0xD13F, 0x06}, ++{0xD140, 0x03}, ++{0xD141, 0xFF}, ++{0xD142, 0xFF}, ++{0xD143, 0xDD}, ++{0xD144, 0xA8}, ++{0xD145, 0x83}, ++{0xD146, 0x40}, ++{0xD147, 0x08}, ++{0xD148, 0x85}, ++{0xD149, 0x21}, ++{0xD14A, 0x00}, ++{0xD14B, 0x00}, ++{0xD14C, 0x85}, ++{0xD14D, 0x41}, ++{0xD14E, 0x00}, ++{0xD14F, 0x04}, ++{0xD150, 0x44}, ++{0xD151, 0x00}, ++{0xD152, 0x48}, ++{0xD153, 0x00}, ++{0xD154, 0x9C}, ++{0xD155, 0x21}, ++{0xD156, 0x00}, ++{0xD157, 0x08}, ++{0x6F0E, 0x03}, ++{0x6F0F, 0x00}, ++{0x460E, 0x08}, ++{0x460F, 0x01}, ++{0x4610, 0x00}, ++{0x4611, 0x01}, ++{0x4612, 0x00}, ++{0x4613, 0x01}, ++{0x4605, 0x08}, // 8bit ++//{0x4709, 0x10}, // swap data bits order [9:0] -> [0:9] ++{0x4608, 0x00}, ++{0x4609, 0x08}, ++{0x6804, 0x00}, ++{0x6805, 0x06}, ++{0x6806, 0x00}, ++{0x5120, 0x00}, ++{0x3510, 0x00}, ++{0x3504, 0x00}, ++{0x6800, 0x00}, ++{0x6F0D, 0x01}, ++{0x4708, 0x01}, // PCLK rising edge ++{0x5000, 0xFF}, ++{0x5001, 0xBF}, ++{0x5002, 0x7E}, ++#ifdef OV10635_DISPLAY_PATTERN ++{0x503d, 0x80}, ++#else ++{0x503D, 0x00}, ++#endif ++{0xC450, 0x01}, /* AA mode */ ++{0xC452, 0x04}, ++{0xC453, 0x00}, ++{0xC454, 0x00}, ++{0xC455, 0x01}, ++{0xC456, 0x01}, ++{0xC457, 0x00}, ++{0xC458, 0x00}, ++{0xC459, 0x00}, ++{0xC45B, 0x00}, ++{0xC45C, 0x01}, ++{0xC45D, 0x00}, ++{0xC45E, 0x00}, ++{0xC45F, 0x00}, ++{0xC460, 0x00}, ++{0xC461, 0x01}, ++{0xC462, 0x01}, ++{0xC464, 0x03}, ++{0xC465, 0x00}, ++{0xC466, 0x8A}, ++{0xC467, 0x00}, ++{0xC468, 0x86}, ++{0xC469, 0x00}, ++{0xC46A, 0x30}, ++{0xC46B, 0x50}, ++{0xC46C, 0x30}, ++{0xC46D, 0x28}, ++{0xC46E, 0x60}, ++{0xC46F, 0x40}, ++{0xC47C, 0x01}, ++{0xC47D, 0x38}, ++{0xC47E, 0x00}, ++{0xC47F, 0x00}, ++{0xC480, 0x00}, ++{0xC481, 0xFF}, ++{0xC482, 0x00}, ++{0xC483, 0x40}, ++{0xC484, 0x00}, ++{0xC485, 0x18}, ++{0xC486, 0x00}, ++{0xC487, 0x18}, ++{0xC488, (OV10635_VTS-8)*16 >> 8}, ++{0xC489, (OV10635_VTS-8)*16 & 0xff}, ++{0xC48A, (OV10635_VTS-8)*16 >> 8}, ++{0xC48B, (OV10635_VTS-8)*16 & 0xff}, ++{0xC48C, 0x00}, ++{0xC48D, 0x04}, ++{0xC48E, 0x00}, ++{0xC48F, 0x04}, ++{0xC490, 0x03}, ++{0xC492, 0x20}, ++{0xC493, 0x08}, ++{0xC498, 0x02}, ++{0xC499, 0x00}, ++{0xC49A, 0x02}, ++{0xC49B, 0x00}, ++{0xC49C, 0x02}, ++{0xC49D, 0x00}, ++{0xC49E, 0x02}, ++{0xC49F, 0x60}, ++{0xC4A0, 0x03}, ++{0xC4A1, 0x00}, ++{0xC4A2, 0x04}, ++{0xC4A3, 0x00}, ++{0xC4A4, 0x00}, ++{0xC4A5, 0x10}, ++{0xC4A6, 0x00}, ++{0xC4A7, 0x40}, ++{0xC4A8, 0x00}, ++{0xC4A9, 0x80}, ++{0xC4AA, 0x0D}, ++{0xC4AB, 0x00}, ++{0xC4AC, 0x0F}, ++{0xC4AD, 0xC0}, ++{0xC4B4, 0x01}, ++{0xC4B5, 0x01}, ++{0xC4B6, 0x00}, ++{0xC4B7, 0x01}, ++{0xC4B8, 0x00}, ++{0xC4B9, 0x01}, ++{0xC4BA, 0x01}, ++{0xC4BB, 0x00}, ++{0xC4BC, 0x01}, ++{0xC4BD, 0x60}, ++{0xC4BE, 0x02}, ++{0xC4BF, 0x33}, ++{0xC4C8, 0x03}, ++{0xC4C9, 0xD0}, ++{0xC4CA, 0x0E}, ++{0xC4CB, 0x00}, ++{0xC4CC, 0x0E}, ++{0xC4CD, 0x51}, ++{0xC4CE, 0x0E}, ++{0xC4CF, 0x51}, ++{0xC4D0, 0x04}, ++{0xC4D1, 0x80}, ++{0xC4E0, 0x04}, ++{0xC4E1, 0x02}, ++{0xC4E2, 0x01}, ++{0xC4E4, 0x10}, ++{0xC4E5, 0x20}, ++{0xC4E6, 0x30}, ++{0xC4E7, 0x40}, ++{0xC4E8, 0x50}, ++{0xC4E9, 0x60}, ++{0xC4EA, 0x70}, ++{0xC4EB, 0x80}, ++{0xC4EC, 0x90}, ++{0xC4ED, 0xA0}, ++{0xC4EE, 0xB0}, ++{0xC4EF, 0xC0}, ++{0xC4F0, 0xD0}, ++{0xC4F1, 0xE0}, ++{0xC4F2, 0xF0}, ++{0xC4F3, 0x80}, ++{0xC4F4, 0x00}, ++{0xC4F5, 0x20}, ++{0xC4F6, 0x02}, ++{0xC4F7, 0x00}, ++{0xC4F8, 0x00}, ++{0xC4F9, 0x00}, ++{0xC4FA, 0x00}, ++{0xC4FB, 0x01}, ++{0xC4FC, 0x01}, ++{0xC4FD, 0x00}, ++{0xC4FE, 0x04}, ++{0xC4FF, 0x02}, ++{0xC500, 0x48}, ++{0xC501, 0x74}, ++{0xC502, 0x58}, ++{0xC503, 0x80}, ++{0xC504, 0x05}, ++{0xC505, 0x80}, ++{0xC506, 0x03}, ++{0xC507, 0x80}, ++{0xC508, 0x01}, ++{0xC509, 0xC0}, ++{0xC50A, 0x01}, ++{0xC50B, 0xA0}, ++{0xC50C, 0x01}, ++{0xC50D, 0x2C}, ++{0xC50E, 0x01}, ++{0xC50F, 0x0A}, ++{0xC510, 0x00}, ++{0xC511, 0x00}, ++{0xC512, 0xE5}, ++{0xC513, 0x14}, ++{0xC514, 0x04}, ++{0xC515, 0x00}, ++{0xC518, OV10635_VTS >> 8}, ++{0xC519, OV10635_VTS & 0xff}, ++{0xC51A, OV10635_HTS >> 8}, ++{0xC51B, OV10635_HTS & 0xff}, ++{0xC2E0, 0x00}, ++{0xC2E1, 0x51}, ++{0xC2E2, 0x00}, ++{0xC2E3, 0xD6}, ++{0xC2E4, 0x01}, ++{0xC2E5, 0x5E}, ++{0xC2E9, 0x01}, ++{0xC2EA, 0x7A}, ++{0xC2EB, 0x90}, ++{0xC2ED, 0x00}, ++{0xC2EE, 0x7A}, ++{0xC2EF, 0x64}, ++{0xC308, 0x00}, ++{0xC309, 0x00}, ++{0xC30A, 0x00}, ++{0xC30C, 0x00}, ++{0xC30D, 0x01}, ++{0xC30E, 0x00}, ++{0xC30F, 0x00}, ++{0xC310, 0x01}, ++{0xC311, 0x60}, ++{0xC312, 0xFF}, ++{0xC313, 0x08}, ++{0xC314, 0x01}, ++{0xC315, 0x00}, /* min saturation gain */ ++{0xC316, 0xFF}, /* max saturation gain */ ++{0xC317, 0x0B}, ++{0xC318, 0x00}, ++{0xC319, 0x0C}, ++{0xC31A, 0x00}, ++{0xC31B, 0xE0}, ++{0xC31C, 0x00}, ++{0xC31D, 0x14}, ++{0xC31E, 0x00}, ++{0xC31F, 0xC5}, ++{0xC320, 0xFF}, ++{0xC321, 0x4B}, ++{0xC322, 0xFF}, ++{0xC323, 0xF0}, ++{0xC324, 0xFF}, ++{0xC325, 0xE8}, ++{0xC326, 0x00}, ++{0xC327, 0x46}, ++{0xC328, 0xFF}, ++{0xC329, 0xD2}, ++{0xC32A, 0xFF}, ++{0xC32B, 0xE4}, ++{0xC32C, 0xFF}, ++{0xC32D, 0xBB}, ++{0xC32E, 0x00}, ++{0xC32F, 0x61}, ++{0xC330, 0xFF}, ++{0xC331, 0xF9}, ++{0xC332, 0x00}, ++{0xC333, 0xD9}, ++{0xC334, 0x00}, ++{0xC335, 0x2E}, ++{0xC336, 0x00}, ++{0xC337, 0xB1}, ++{0xC338, 0xFF}, ++{0xC339, 0x64}, ++{0xC33A, 0xFF}, ++{0xC33B, 0xEB}, ++{0xC33C, 0xFF}, ++{0xC33D, 0xE8}, ++{0xC33E, 0x00}, ++{0xC33F, 0x48}, ++{0xC340, 0xFF}, ++{0xC341, 0xD0}, ++{0xC342, 0xFF}, ++{0xC343, 0xED}, ++{0xC344, 0xFF}, ++{0xC345, 0xAD}, ++{0xC346, 0x00}, ++{0xC347, 0x66}, ++{0xC348, 0x01}, ++{0xC349, 0x00}, ++{0x6700, 0x04}, ++{0x6701, 0x7B}, ++{0x6702, 0xFD}, ++{0x6703, 0xF9}, ++{0x6704, 0x3D}, ++{0x6705, 0x71}, ++{0x6706, 0x78}, ++{0x6708, 0x05}, ++{0x6F06, 0x6F}, ++{0x6F07, 0x00}, ++{0x6F0A, 0x6F}, ++{0x6F0B, 0x00}, ++{0x6F00, 0x03}, ++{0xC34C, 0x01}, ++{0xC34D, 0x00}, ++{0xC34E, 0x46}, ++{0xC34F, 0x55}, ++{0xC350, 0x00}, ++{0xC351, 0x40}, ++{0xC352, 0x00}, ++{0xC353, 0xFF}, ++{0xC354, 0x04}, ++{0xC355, 0x08}, ++{0xC356, 0x01}, ++{0xC357, 0xEF}, ++{0xC358, 0x30}, ++{0xC359, 0x01}, ++{0xC35A, 0x64}, ++{0xC35B, 0x46}, ++{0xC35C, 0x00}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0x3042, 0xF0}, ++{0xC261, 0x01}, ++{0x301B, 0xF0}, ++{0x301C, 0xF0}, ++{0x301A, 0xF0}, ++{0x6F00, 0xC3}, ++{0xC46A, 0x30}, ++{0xC46D, 0x20}, ++{0xC464, 0x84}, ++{0xC465, 0x00}, ++{0x6F00, 0x03}, ++{0x6F00, 0x43}, ++{0x381C, 0x00}, ++{0x381D, 0x40}, ++{0xC454, 0x01}, ++{0x6F00, 0xC3}, ++{0xC454, 0x00}, ++{0xC4B1, 0x02}, ++{0xC4B2, 0x01}, ++{0xC4B3, 0x03}, ++{0x6F00, 0x03}, ++{0x6F00, 0x43}, ++/* enable FSIN (FRAMESYNC input) functionality */ ++{0x3832, (0x0d+2*0x20+0x15+38) >> 8}, ++{0x3833, (0x0d+2*0x20+0x15+38) & 0xff}, ++{0x3834, OV10635_VTS >> 8}, ++{0x3835, OV10635_VTS & 0xff}, ++{0x302E, 0x01}, ++}; ++ ++static const struct ov10635_reg ov10635_regs_30fps[] = { ++/* disable clocks */ ++{0x301b, 0xff}, ++{0x301c, 0xff}, ++{0x301a, 0xff}, ++/* clk = 24Mhz/2*32/2(1+1)=96Mhz, 30fps */ ++{0x3003, 0x20}, ++{0x3004, 0x21}, ++/* enable clocks */ ++{0x301b, 0xf0}, ++{0x301c, 0xf0}, ++{0x301a, 0xf0}, ++}; + -+ priv->rect.left = 0; -+ priv->rect.top = 0; -+ priv->rect.width = priv->max_width; -+ priv->rect.height = priv->max_height; ++static const struct ov10635_reg ov10635_regs_15fps[] = { ++/* disable clocks */ ++{0x301b, 0xff}, ++{0x301c, 0xff}, ++{0x301a, 0xff}, ++/* clk = 24Mhz/2*32/2(1+3)=48Mhz, 15fps */ ++{0x3003, 0x20}, ++{0x3004, 0x23}, ++/* enable clocks */ ++{0x301b, 0xf0}, ++{0x301c, 0xf0}, ++{0x301a, 0xf0}, ++}; + -+ ret = v4l2_async_register_subdev(&priv->sd); -+ if (ret) -+ goto cleanup; ++static const struct ov10635_reg ov10635_regs_10fps[] = { ++/* disable clocks */ ++{0x301b, 0xff}, ++{0x301c, 0xff}, ++{0x301a, 0xff}, ++/* clk = 24Mhz/2*32/2(1+5)=32Mhz, 10fps */ ++{0x3003, 0x20}, ++{0x3004, 0x25}, ++/* enable clocks */ ++{0x301b, 0xf0}, ++{0x301c, 0xf0}, ++{0x301a, 0xf0}, ++}; + -+ if (device_create_file(&client->dev, &dev_attr_otp_id_ov490) != 0) { -+ dev_err(&client->dev, "sysfs otp_id entry creation failed\n"); -+ goto cleanup; -+ } ++static const struct ov10635_reg ov10635_regs_5fps[] = { ++/* disable clocks */ ++{0x301b, 0xff}, ++{0x301c, 0xff}, ++{0x301a, 0xff}, ++/* clk = 24Mhz/4*32/2(1+5)=96Mhz, 5fps */ ++{0x3003, 0x20}, ++{0x3004, 0x45}, ++/* enable clocks */ ++{0x301b, 0xf0}, ++{0x301c, 0xf0}, ++{0x301a, 0xf0}, ++}; + -+ priv->init_complete = 1; ++static const struct ov10635_reg ov10635_regs_contrast[5][18] = { ++{ ++ {0x6f00, 0xc3}, ++ {0xc4e4, 0x20}, ++ {0xc4e5, 0x40}, ++ {0xc4e6, 0x60}, ++ {0xc4e7, 0x80}, ++ {0xc4e8, 0xa0}, ++ {0xc4e9, 0xb4}, ++ {0xc4ea, 0xc0}, ++ {0xc4eb, 0xcb}, ++ {0xc4ec, 0xd5}, ++ {0xc4ed, 0xde}, ++ {0xc4ee, 0xe6}, ++ {0xc4ef, 0xed}, ++ {0xc4f0, 0xf3}, ++ {0xc4f1, 0xf8}, ++ {0xc4f2, 0xfc}, ++ {0x6f00, 0x03}, ++ {0x6f00, 0x43}, ++}, { ++ {0x6f00, 0xc3}, ++ {0xc4e4, 0x18}, ++ {0xc4e5, 0x30}, ++ {0xc4e6, 0x48}, ++ {0xc4e7, 0x60}, ++ {0xc4e8, 0x78}, ++ {0xc4e9, 0x90}, ++ {0xc4ea, 0xa4}, ++ {0xc4eb, 0xb4}, ++ {0xc4ec, 0xc2}, ++ {0xc4ed, 0xcf}, ++ {0xc4ee, 0xdb}, ++ {0xc4ef, 0xe5}, ++ {0xc4f0, 0xee}, ++ {0xc4f1, 0xf6}, ++ {0xc4f2, 0xfc}, ++ {0x6f00, 0x03}, ++ {0x6f00, 0x43}, ++}, { ++ {0x6f00, 0xc3}, ++ {0xc4e4, 0x10}, ++ {0xc4e5, 0x20}, ++ {0xc4e6, 0x30}, ++ {0xc4e7, 0x40}, ++ {0xc4e8, 0x50}, ++ {0xc4e9, 0x60}, ++ {0xc4ea, 0x70}, ++ {0xc4eb, 0x80}, ++ {0xc4ec, 0x90}, ++ {0xc4ed, 0xa0}, ++ {0xc4ee, 0xb0}, ++ {0xc4ef, 0xc0}, ++ {0xc4f0, 0xd0}, ++ {0xc4f1, 0xe0}, ++ {0xc4f2, 0xf0}, ++ {0x6f00, 0x03}, ++ {0x6f00, 0x43}, ++}, { ++ {0x6f00, 0xc3}, ++ {0xc4e4, 0x0c}, ++ {0xc4e5, 0x18}, ++ {0xc4e6, 0x24}, ++ {0xc4e7, 0x30}, ++ {0xc4e8, 0x3c}, ++ {0xc4e9, 0x48}, ++ {0xc4ea, 0x54}, ++ {0xc4eb, 0x62}, ++ {0xc4ec, 0x72}, ++ {0xc4ed, 0x84}, ++ {0xc4ee, 0x94}, ++ {0xc4ef, 0xa6}, ++ {0xc4f0, 0xb9}, ++ {0xc4f1, 0xcd}, ++ {0xc4f2, 0xe2}, ++ {0x6f00, 0x03}, ++ {0x6f00, 0x43}, ++}, { ++ {0x6f00, 0xc3}, ++ {0xc4e4, 0x06}, ++ {0xc4e5, 0x0d}, ++ {0xc4e6, 0x15}, ++ {0xc4e7, 0x1e}, ++ {0xc4e8, 0x28}, ++ {0xc4e9, 0x32}, ++ {0xc4ea, 0x3c}, ++ {0xc4eb, 0x48}, ++ {0xc4ec, 0x56}, ++ {0xc4ed, 0x66}, ++ {0xc4ee, 0x78}, ++ {0xc4ef, 0x8c}, ++ {0xc4f0, 0xa2}, ++ {0xc4f1, 0xba}, ++ {0xc4f2, 0xd4}, ++ {0x6f00, 0x03}, ++ {0x6f00, 0x43}, ++} ++}; +diff --git a/drivers/media/i2c/soc_camera/ov10635_debug.h b/drivers/media/i2c/soc_camera/ov10635_debug.h +new file mode 100644 +index 0000000..4c3515a +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/ov10635_debug.h +@@ -0,0 +1,54 @@ + -+ return 0; ++#if 0 ++{0x4700, 0x02}, // BT656 ++{0x381d, 0x40}, // mirror off ++{0x381c, 0x00}, // flip off ++{0x4300, 0x3a}, // YUV: UYVY ++{0x4708, 0x00}, // PCLK rising edge + -+cleanup: -+ media_entity_cleanup(&priv->sd.entity); -+ v4l2_ctrl_handler_free(&priv->hdl); -+ v4l2_device_unregister_subdev(&priv->sd); -+#ifdef CONFIG_SOC_CAMERA_OV490_OV10640 -+ v4l_err(client, "failed to probe @ 0x%02x (%s)\n", -+ client->addr, client->adapter->name); ++// clk = 24Mhz/3*22/2= 88Mhz ++{0x3003, 0x16}, ++{0x3004, 0x30}, +#endif -+ return ret; -+} + -+static int ov490_remove(struct i2c_client *client) -+{ -+ struct ov490_priv *priv = i2c_get_clientdata(client); ++#define WIDTH 1280 ++#define HEIGHT 720 + -+ device_remove_file(&client->dev, &dev_attr_otp_id_ov490); -+ v4l2_async_unregister_subdev(&priv->sd); -+ media_entity_cleanup(&priv->sd.entity); -+ v4l2_ctrl_handler_free(&priv->hdl); -+ v4l2_device_unregister_subdev(&priv->sd); ++// DVP frame size ++{0x3808, WIDTH >> 8}, ++{0x3809, WIDTH & 0xff}, ++{0x380a, HEIGHT >> 8}, ++{0x380b, HEIGHT & 0xff}, + -+ return 0; -+} ++{0x3802, ((814 - HEIGHT)/2) >> 8}, // vert crop start ++{0x3803, ((814 - HEIGHT)/2) & 0xff}, ++{0x3806, ((814 - HEIGHT)/2 + HEIGHT + 1) >> 8}, // vert crop end ++{0x3807, ((814 - HEIGHT)/2 + HEIGHT + 1) & 0xff}, + -+#ifdef CONFIG_SOC_CAMERA_OV490_OV10640 -+static const struct i2c_device_id ov490_id[] = { -+ { "ov490-ov10640", 0 }, -+ { } -+}; -+MODULE_DEVICE_TABLE(i2c, ov490_id); ++#if 0 ++#define HTS 0x6f6 // got from above table 1782 ++#define VTS (0x2ec+80) // got from above table 748 + 80 + -+static const struct of_device_id ov490_of_ids[] = { -+ { .compatible = "ovti,ov490-ov10640", }, -+ { } -+}; -+MODULE_DEVICE_TABLE(of, ov490_of_ids); ++{0x380c, HTS >> 8}, // hts ++{0x380d, HTS & 0xff}, ++{0x380e, VTS >> 8}, // vts ++{0x380f, VTS & 0xff}, + -+static struct i2c_driver ov490_i2c_driver = { -+ .driver = { -+ .name = "ov490-ov10640", -+ .of_match_table = ov490_of_ids, -+ }, -+ .probe = ov490_probe, -+ .remove = ov490_remove, -+ .id_table = ov490_id, -+}; ++// fifo ++{0x4606, (2*HTS) >> 8}, // fifo_line_length = 2*hts ++{0x4607, (2*HTS) & 0xff}, ++{0x460a, (2*(HTS-1280)) >> 8}, // fifo_hsync_start = 2*(hts - xres) ++{0x460b, (2*(HTS-1280)) & 0xff }, + -+module_i2c_driver(ov490_i2c_driver); ++// exposure ++{0xC488, (VTS-8)*16 >> 8}, ++{0xC489, (VTS-8)*16 & 0xff}, ++{0xC48A, (VTS-8)*16 >> 8}, ++{0xC48B, (VTS-8)*16 & 0xff}, + -+MODULE_DESCRIPTION("SoC Camera driver for OV490-OV10640"); -+MODULE_AUTHOR("Vladimir Barinov"); -+MODULE_LICENSE("GPL"); ++// vts/hts ++{0xC518, VTS >> 8}, ++{0xC519, VTS & 0xff}, ++{0xC51A, HTS >> 8}, ++{0xC51B, HTS & 0xff}, +#endif -diff --git a/drivers/media/i2c/soc_camera/ov490_ov10640.h b/drivers/media/i2c/soc_camera/ov490_ov10640.h +diff --git a/drivers/media/i2c/soc_camera/ov106xx.c b/drivers/media/i2c/soc_camera/ov106xx.c new file mode 100644 -index 0000000..b22e93e +index 0000000..1dca809 --- /dev/null -+++ b/drivers/media/i2c/soc_camera/ov490_ov10640.h -@@ -0,0 +1,102 @@ ++++ b/drivers/media/i2c/soc_camera/ov106xx.c +@@ -0,0 +1,128 @@ +/* -+ * OmniVision ov490-ov10640 sensor camera wizard 1280x1080@30/UYVY/BT601/8bit ++ * OmniVision ov10635/ov490-ov10640/ov495-ov2775 sensor camera driver + * + * Copyright (C) 2016-2017 Cogent Embedded, Inc. + * @@ -5795,107 +5068,133 @@ index 0000000..b22e93e + * option) any later version. + */ + -+//#define OV490_DISPLAY_PATTERN ++#include "ov10635.c" ++#include "ov490_ov10640.c" ++#include "ov495_ov2775.c" ++#include "ar0132.c" ++#include "ar0220.c" ++#include "ap0101_ar014x.c" + -+struct ov490_reg { -+ u16 reg; -+ u8 val; -+}; ++static enum { ++ ID_OV10635, ++ ID_OV490_OV10640, ++ ID_OV495_OV2775, ++ ID_AR0132, ++ ID_AR0220, ++ ID_AP0101_AR014X, ++} chip_id; + -+static const struct ov490_reg ov490_regs_wizard[] = { -+/* The following registers should match firmware */ -+{0xfffd, 0x80}, -+{0xfffe, 0x82}, -+{0x0071, 0x11}, -+{0x0075, 0x11}, -+{0xfffe, 0x29}, -+{0x6010, 0x01}, -+/* ov490 EMB line disable in YUV and RAW data, NOTE: EMB line is still used in ISP and sensor */ -+{0xe000, 0x14}, -+#if 0 /* do not disable EMB line in ISP! */ -+{0x4017, 0x00}, -+#endif -+{0xfffe, 0x28}, -+{0x6000, 0x04}, -+{0x6004, 0x00}, -+{0x6008, 0x00}, // PCLK polarity - useless due to silicon bug -> use 0x808000bb register -+{0xfffe, 0x80}, -+{0x0091, 0x00}, -+{0x00bb, 0x1d}, // bit[3]=0 - PCLK polarity workaround -+/* ov10640 EMB line disable */ -+#if 0 /* do not disable EMB line in sensor! */ -+{0xfffe, 0x19}, -+{0x5000, 0x00}, -+{0x5001, 0x30}, -+{0x5002, 0x91}, -+{0x5003, 0x08}, -+{0xfffe, 0x80}, -+{0x00c0, 0xc1}, -+#endif -+/* Ov490 FSIN: app_fsin_from_fsync */ -+{0xfffe, 0x85}, -+{0x0008, 0x00}, -+{0x0009, 0x01}, -+{0x000A, 0x05}, // fsin0 src -+{0x000B, 0x00}, -+{0x0030, 0x02}, // fsin0_delay -+{0x0031, 0x00}, -+{0x0032, 0x00}, -+{0x0033, 0x00}, -+{0x0038, 0x02}, // fsin1_delay -+{0x0039, 0x00}, -+{0x003A, 0x00}, -+{0x003B, 0x00}, -+{0x0070, 0x2C}, // fsin0_length -+{0x0071, 0x01}, -+{0x0072, 0x00}, -+{0x0073, 0x00}, -+{0x0074, 0x64}, // fsin1_length -+{0x0075, 0x00}, -+{0x0076, 0x00}, -+{0x0077, 0x00}, -+{0x0000, 0x14}, -+{0x0001, 0x00}, -+{0x0002, 0x00}, -+{0x0003, 0x00}, -+{0x0004, 0x32}, // load fsin0,load fsin1,load other, it will be cleared automatically. -+{0x0005, 0x00}, -+{0x0006, 0x00}, -+{0x0007, 0x00}, -+{0xfffe, 0x80}, -+{0x0081, 0x00}, // 03;SENSOR FSIN -+/* ov10640 FSIN */ -+{0xfffe, 0x19}, -+{0x5000, 0x00}, -+{0x5001, 0x30}, -+{0x5002, 0x8c}, -+{0x5003, 0xb2}, -+{0xfffe, 0x80}, -+{0x00c0, 0xc1}, -+/* ov10640 HFLIP=1 by default */ -+{0xfffe, 0x19}, -+{0x5000, 0x01}, -+{0x5001, 0x00}, -+{0xfffe, 0x80}, -+{0x00c0, 0xdc}, -+#ifdef OV490_DISPLAY_PATTERN -+{0xfffd, 0x80}, -+{0xfffe, 0x19}, -+{0x5000, 0x02}, -+{0xfffe, 0x80}, -+{0x00c0, 0xd6}, -+#endif ++static int ov106xx_probe(struct i2c_client *client, ++ const struct i2c_device_id *did) ++{ ++ int ret; ++ chip_id = -EINVAL; ++ ++ ret = ov10635_probe(client, did); ++ if (!ret) { ++ chip_id = ID_OV10635; ++ goto out; ++ } ++ ++ ret = ov490_probe(client, did); ++ if (!ret) { ++ chip_id = ID_OV490_OV10640; ++ goto out; ++ } ++ ++ ret = ov495_probe(client, did); ++ if (!ret) { ++ chip_id = ID_OV495_OV2775; ++ goto out; ++ } ++ ++ ret = ar0132_probe(client, did); ++ if (!ret) { ++ chip_id = ID_AR0132; ++ goto out; ++ } ++ ++ ret = ar0220_probe(client, did); ++ if (!ret) { ++ chip_id = ID_AR0220; ++ goto out; ++ } ++ ++ ret = ap0101_probe(client, did); ++ if (!ret) { ++ chip_id = ID_AP0101_AR014X; ++ goto out; ++ } ++ ++ v4l_err(client, "failed to probe @ 0x%02x (%s)\n", ++ client->addr, client->adapter->name); ++out: ++ return ret; ++} ++ ++static int ov106xx_remove(struct i2c_client *client) ++{ ++ switch (chip_id) { ++ case ID_OV10635: ++ ov10635_remove(client); ++ break; ++ case ID_OV490_OV10640: ++ ov490_remove(client); ++ break; ++ case ID_OV495_OV2775: ++ ov495_remove(client); ++ break; ++ case ID_AR0132: ++ ar0132_remove(client); ++ break; ++ case ID_AR0220: ++ ar0220_remove(client); ++ break; ++ case ID_AP0101_AR014X: ++ ap0101_remove(client); ++ break; ++ }; ++ ++ return 0; ++} ++ ++static const struct i2c_device_id ov106xx_id[] = { ++ { "ov106xx", 0 }, ++ { } +}; -diff --git a/drivers/media/i2c/soc_camera/ov495_ov2775.c b/drivers/media/i2c/soc_camera/ov495_ov2775.c ++MODULE_DEVICE_TABLE(i2c, ov106xx_id); ++ ++static const struct of_device_id ov106xx_of_ids[] = { ++ { .compatible = "ovti,ov106xx", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, ov106xx_of_ids); ++ ++static struct i2c_driver ov106xx_i2c_driver = { ++ .driver = { ++ .name = "ov106xx", ++ .of_match_table = ov106xx_of_ids, ++ }, ++ .probe = ov106xx_probe, ++ .remove = ov106xx_remove, ++ .id_table = ov106xx_id, ++}; ++ ++module_i2c_driver(ov106xx_i2c_driver); ++ ++MODULE_DESCRIPTION("SoC Camera driver for OV10635, OV490/OV10640, OV495/OV2775, AR0132, AR0220, AP0101/AR014X"); ++MODULE_AUTHOR("Vladimir Barinov"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/media/i2c/soc_camera/ov490_ov10640.c b/drivers/media/i2c/soc_camera/ov490_ov10640.c new file mode 100644 -index 0000000..6dc0675 +index 0000000..812f367 --- /dev/null -+++ b/drivers/media/i2c/soc_camera/ov495_ov2775.c -@@ -0,0 +1,658 @@ ++++ b/drivers/media/i2c/soc_camera/ov490_ov10640.c +@@ -0,0 +1,1133 @@ +/* -+ * OmniVision ov495-ov2775 sensor camera driver ++ * OmniVision ov490-ov10640 sensor camera driver + * -+ * Copyright (C) 2017 Cogent Embedded, Inc. ++ * Copyright (C) 2016-2018 Cogent Embedded, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the @@ -5914,62 +5213,120 @@ index 0000000..6dc0675 +#include +#include + -+#include "ov495_ov2775.h" ++#include "max9286.h" ++#include "ov490_ov10640.h" + -+#define OV495_I2C_ADDR 0x24 ++#define OV490_I2C_ADDR 0x24 + -+#define OV495_PID 0x300a -+#define OV495_VER 0x300b -+#define OV495_VERSION_REG 0x0495 -+#define OV495_VERSION(pid, ver) (((pid) << 8) | ((ver) & 0xff)) ++#define OV490_PID 0x300a ++#define OV490_VER 0x300b ++#define OV490_VERSION_REG 0x0490 ++#define OV490_VERSION(pid, ver) (((pid) << 8) | ((ver) & 0xff)) + -+#define OV495_ISP_HSIZE_LOW 0x60 -+#define OV495_ISP_HSIZE_HIGH 0x61 -+#define OV495_ISP_VSIZE_LOW 0x62 -+#define OV495_ISP_VSIZE_HIGH 0x63 ++#define OV490_ISP_HSIZE_LOW 0x60 ++#define OV490_ISP_HSIZE_HIGH 0x61 ++#define OV490_ISP_VSIZE_LOW 0x62 ++#define OV490_ISP_VSIZE_HIGH 0x63 + -+struct ov495_priv { ++struct ov490_priv { + struct v4l2_subdev sd; + struct v4l2_ctrl_handler hdl; + struct media_pad pad; + struct v4l2_rect rect; + int max_width; + int max_height; ++ char is_fixed_sensor; + int init_complete; + u8 id[6]; + int exposure; + int gain; + int autogain; ++ int red; ++ int green_r; ++ int green_b; ++ int blue; ++ int awb; ++ int dvp_order; + /* serializers */ + int max9286_addr; + int max9271_addr; -+ int ti960_addr; -+ int ti954_addr; ++ int ti9x4_addr; + int ti9x3_addr; + int port; + int gpio_resetb; ++ int active_low_resetb; + int gpio_fsin; -+ +}; + -+static int force_conf_link; ++static int conf_link; ++module_param(conf_link, int, 0644); ++MODULE_PARM_DESC(conf_link, " Force configuration link. Used only if robust firmware flashing required (f.e. recovery)"); + -+static __init int ov495_force_conf_link(char *str) ++static int dvp_order; ++module_param(dvp_order, int, 0644); ++MODULE_PARM_DESC(dvp_order, " DVP bus bits order"); ++ ++static int max_width; ++module_param(max_width, int, 0644); ++MODULE_PARM_DESC(max_width, " Fixed sensor width"); ++ ++static int max_height; ++module_param(max_height, int, 0644); ++MODULE_PARM_DESC(max_height, " Fixed sensor height"); ++ ++static inline struct ov490_priv *to_ov490(const struct i2c_client *client) +{ -+ /* force configuration link */ -+ /* used only if robust firmware flashing required (f.e. recovery) */ -+ force_conf_link = 1; -+ return 0; ++ return container_of(i2c_get_clientdata(client), struct ov490_priv, sd); +} -+early_param("force_conf_link", ov495_force_conf_link); + -+static inline struct ov495_priv *to_ov495(const struct i2c_client *client) ++static void ov490_s_port(struct i2c_client *client, int fwd_en) +{ -+ return container_of(i2c_get_clientdata(client), struct ov495_priv, sd); ++ struct ov490_priv *priv = to_ov490(client); ++ int tmp_addr; ++ ++ if (priv->max9286_addr) { ++ tmp_addr = client->addr; ++ client->addr = priv->max9286_addr; /* Deserializer I2C address */ ++ reg8_write(client, 0x0a, fwd_en ? 0x11 << priv->port : 0); /* Enable/disable reverse/forward control for this port */ ++ usleep_range(5000, 5500); /* wait 5ms */ ++ client->addr = tmp_addr; ++ }; +} + -+static int ov495_set_regs(struct i2c_client *client, -+ const struct ov495_reg *regs, int nr_regs) ++static void ov490_reset(struct i2c_client *client) ++{ ++ struct ov490_priv *priv = to_ov490(client); ++ int tmp_addr; ++ ++ if (priv->max9286_addr) { ++ if (priv->gpio_resetb < 1 || priv->gpio_resetb > 5) ++ return; ++ ++ tmp_addr = client->addr; ++ /* get out from sensor reset */ ++ client->addr = priv->max9271_addr; /* MAX9271 I2C address */ ++ reg8_write(client, 0x0f, (0xfe & ~BIT(priv->gpio_resetb)) | ++ (priv->active_low_resetb ? 0 : BIT(priv->gpio_resetb))); /* set GPIOn value to reset */ ++ usleep_range(2000, 2500); /* wait 2ms */ ++ reg8_write(client, 0x0f, (0xfe & ~BIT(priv->gpio_resetb)) | ++ (priv->active_low_resetb ? BIT(priv->gpio_resetb) : 0)); /* set GPIOn value to un-reset */ ++ usleep_range(2000, 2500); /* wait 2ms */ ++ client->addr = tmp_addr; ++ } ++ ++ if (priv->ti9x4_addr) { ++ client->addr = priv->ti9x4_addr; /* TI9x4 I2C address */ ++ ++ reg8_write(client, 0x4c, (priv->port << 4) | (1 << priv->port)); /* Select RX port number */ ++ usleep_range(2000, 2500); /* wait 2ms */ ++ reg8_write(client, 0x6e, 0x8a); /* set GPIO1 value to reset */ ++ usleep_range(2000, 2500); /* wait 2ms */ ++ reg8_write(client, 0x6e, 0x9a); /* set GPIO1 value to un-reset */ ++ } ++} ++ ++static int ov490_set_regs(struct i2c_client *client, ++ const struct ov490_reg *regs, int nr_regs) +{ + int i; + @@ -5983,18 +5340,54 @@ index 0000000..6dc0675 + return 0; +} + -+static int ov495_s_stream(struct v4l2_subdev *sd, int enable) ++static u8 ov490_ov10640_read(struct i2c_client *client, u16 addr) ++{ ++ u8 reg_val = 0; ++ ++ reg16_write(client, 0xFFFD, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ reg16_write(client, 0x5000, 0x01); /* read operation */ ++ reg16_write(client, 0x5001, addr >> 8); ++ reg16_write(client, 0x5002, addr & 0xff); ++ reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ reg16_write(client, 0x00C0, 0xc1); ++ reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(1000, 1500); /* wait 1 ms */ ++ reg16_read(client, 0x5000, ®_val); ++ ++ return reg_val; ++} ++ ++static void ov490_ov10640_write(struct i2c_client *client, u16 addr, u8 val) ++{ ++ reg16_write(client, 0xFFFD, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ reg16_write(client, 0x5000, 0x00); /* write operation */ ++ reg16_write(client, 0x5001, addr >> 8); ++ reg16_write(client, 0x5002, addr & 0xff); ++ reg16_write(client, 0x5003, val); ++ reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ reg16_write(client, 0x00C0, 0xc1); ++} ++ ++static int ov490_s_stream(struct v4l2_subdev *sd, int enable) +{ + return 0; +} + -+static int ov495_get_fmt(struct v4l2_subdev *sd, ++static int ov490_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *mf = &format->format; + struct i2c_client *client = v4l2_get_subdevdata(sd); -+ struct ov495_priv *priv = to_ov495(client); ++ struct ov490_priv *priv = to_ov490(client); + + if (format->pad) + return -EINVAL; @@ -6008,7 +5401,7 @@ index 0000000..6dc0675 + return 0; +} + -+static int ov495_set_fmt(struct v4l2_subdev *sd, ++static int ov490_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ @@ -6024,7 +5417,7 @@ index 0000000..6dc0675 + return 0; +} + -+static int ov495_enum_mbus_code(struct v4l2_subdev *sd, ++static int ov490_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ @@ -6036,28 +5429,28 @@ index 0000000..6dc0675 + return 0; +} + -+static int ov495_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) ++static int ov490_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); -+ struct ov495_priv *priv = to_ov495(client); ++ struct ov490_priv *priv = to_ov490(client); + + memcpy(edid->edid, priv->id, 6); + + edid->edid[6] = 0xff; + edid->edid[7] = client->addr; -+ edid->edid[8] = OV495_VERSION_REG >> 8; -+ edid->edid[9] = OV495_VERSION_REG & 0xff; ++ edid->edid[8] = OV490_VERSION_REG >> 8; ++ edid->edid[9] = OV490_VERSION_REG & 0xff; + + return 0; +} + -+static int ov495_set_selection(struct v4l2_subdev *sd, ++static int ov490_set_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + struct v4l2_rect *rect = &sel->r; + struct i2c_client *client = v4l2_get_subdevdata(sd); -+ struct ov495_priv *priv = to_ov495(client); ++ struct ov490_priv *priv = to_ov490(client); + + if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || + sel->target != V4L2_SEL_TGT_CROP) @@ -6080,12 +5473,12 @@ index 0000000..6dc0675 + return 0; +} + -+static int ov495_get_selection(struct v4l2_subdev *sd, ++static int ov490_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); -+ struct ov495_priv *priv = to_ov495(client); ++ struct ov490_priv *priv = to_ov490(client); + + if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) + return -EINVAL; @@ -6111,7 +5504,7 @@ index 0000000..6dc0675 + } +} + -+static int ov495_g_mbus_config(struct v4l2_subdev *sd, ++static int ov490_g_mbus_config(struct v4l2_subdev *sd, + struct v4l2_mbus_config *cfg) +{ + cfg->flags = V4L2_MBUS_CSI2_1_LANE | V4L2_MBUS_CSI2_CHANNEL_0 | @@ -6122,7 +5515,7 @@ index 0000000..6dc0675 +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG -+static int ov495_g_register(struct v4l2_subdev *sd, ++static int ov490_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -6139,7 +5532,7 @@ index 0000000..6dc0675 + return 0; +} + -+static int ov495_s_register(struct v4l2_subdev *sd, ++static int ov490_s_register(struct v4l2_subdev *sd, + const struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -6154,18 +5547,29 @@ index 0000000..6dc0675 +} +#endif + -+static struct v4l2_subdev_core_ops ov495_core_ops = { ++static struct v4l2_subdev_core_ops ov490_core_ops = { +#ifdef CONFIG_VIDEO_ADV_DEBUG -+ .g_register = ov495_g_register, -+ .s_register = ov495_s_register, ++ .g_register = ov490_g_register, ++ .s_register = ov490_s_register, +#endif +}; + -+static int ov495_s_ctrl(struct v4l2_ctrl *ctrl) ++static int ov490_s_gamma(int a, int ref) ++{ ++ if ((a + ref) > 0xff) ++ return 0xff; ++ ++ if ((a + ref) < 0) ++ return 0; ++ ++ return a + ref; ++} ++ ++static int ov490_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct v4l2_subdev *sd = to_sd(ctrl); + struct i2c_client *client = v4l2_get_subdevdata(sd); -+ struct ov495_priv *priv = to_ov495(client); ++ struct ov490_priv *priv = to_ov490(client); + int ret = -EINVAL; + + if (!priv->init_complete) @@ -6173,38 +5577,316 @@ index 0000000..6dc0675 + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: ++ /* SDE (rough) brightness */ ++ ret = reg16_write(client, 0xFFFD, 0x80); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, 0x00); ++ ret |= reg16_write(client, 0x5001, ctrl->val); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xf1); + break; + case V4L2_CID_CONTRAST: ++ ret = reg16_write(client, 0xFFFD, 0x80); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, ctrl->val); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xfd); + break; + case V4L2_CID_SATURATION: ++ ret = reg16_write(client, 0xFFFD, 0x80); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, ctrl->val); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xf3); + break; + case V4L2_CID_HUE: ++ ret = reg16_write(client, 0xFFFD, 0x80); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, ctrl->val); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xf5); + break; + case V4L2_CID_GAMMA: ++ ret = reg16_write(client, 0xFFFD, 0x80); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, ov490_s_gamma(ctrl->val, 0x12)); ++ ret |= reg16_write(client, 0x5001, ov490_s_gamma(ctrl->val, 0x20)); ++ ret |= reg16_write(client, 0x5002, ov490_s_gamma(ctrl->val, 0x3b)); ++ ret |= reg16_write(client, 0x5003, ov490_s_gamma(ctrl->val, 0x5d)); ++ ret |= reg16_write(client, 0x5004, ov490_s_gamma(ctrl->val, 0x6a)); ++ ret |= reg16_write(client, 0x5005, ov490_s_gamma(ctrl->val, 0x76)); ++ ret |= reg16_write(client, 0x5006, ov490_s_gamma(ctrl->val, 0x81)); ++ ret |= reg16_write(client, 0x5007, ov490_s_gamma(ctrl->val, 0x8b)); ++ ret |= reg16_write(client, 0x5008, ov490_s_gamma(ctrl->val, 0x96)); ++ ret |= reg16_write(client, 0x5009, ov490_s_gamma(ctrl->val, 0x9e)); ++ ret |= reg16_write(client, 0x500a, ov490_s_gamma(ctrl->val, 0xae)); ++ ret |= reg16_write(client, 0x500b, ov490_s_gamma(ctrl->val, 0xbc)); ++ ret |= reg16_write(client, 0x500c, ov490_s_gamma(ctrl->val, 0xcf)); ++ ret |= reg16_write(client, 0x500d, ov490_s_gamma(ctrl->val, 0xde)); ++ ret |= reg16_write(client, 0x500e, ov490_s_gamma(ctrl->val, 0xec)); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xf9); + break; + case V4L2_CID_SHARPNESS: ++ ret = reg16_write(client, 0xFFFD, 0x80); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, ctrl->val); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xfb); + break; + case V4L2_CID_AUTOGAIN: + case V4L2_CID_GAIN: + case V4L2_CID_EXPOSURE: ++ if (ctrl->id == V4L2_CID_AUTOGAIN) ++ priv->autogain = ctrl->val; ++ if (ctrl->id == V4L2_CID_GAIN) ++ priv->gain = ctrl->val; ++ if (ctrl->id == V4L2_CID_EXPOSURE) ++ priv->exposure = ctrl->val; ++ ++ ret = reg16_write(client, 0xFFFD, 0x80); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, !priv->autogain); ++ ret |= reg16_write(client, 0x5001, priv->exposure >> 8); ++ ret |= reg16_write(client, 0x5002, priv->exposure & 0xff); ++ ret |= reg16_write(client, 0x5003, priv->exposure >> 8); ++ ret |= reg16_write(client, 0x5004, priv->exposure & 0xff); ++ ret |= reg16_write(client, 0x5005, priv->exposure >> 8); ++ ret |= reg16_write(client, 0x5006, priv->exposure & 0xff); ++ ret |= reg16_write(client, 0x5007, priv->gain >> 8); ++ ret |= reg16_write(client, 0x5008, priv->gain & 0xff); ++ ret |= reg16_write(client, 0x5009, priv->gain >> 8); ++ ret |= reg16_write(client, 0x500a, priv->gain & 0xff); ++ ret |= reg16_write(client, 0x500b, priv->gain >> 8); ++ ret |= reg16_write(client, 0x500c, priv->gain & 0xff); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xea); ++ break; ++ case V4L2_CID_AUTO_WHITE_BALANCE: ++ case V4L2_CID_RED_BALANCE: ++ case V4L2_CID_BLUE_BALANCE: ++ if (ctrl->id == V4L2_CID_AUTO_WHITE_BALANCE) ++ priv->awb = ctrl->val; ++ if (ctrl->id == V4L2_CID_RED_BALANCE) { ++ priv->red = ctrl->val; ++ priv->red <<= 8; ++ priv->green_r = priv->red / 2; ++ } ++ if (ctrl->id == V4L2_CID_BLUE_BALANCE) { ++ priv->blue = ctrl->val; ++ priv->blue <<= 8; ++ priv->green_b = priv->blue / 2; ++ } ++ ++ ret = reg16_write(client, 0xFFFD, 0x80); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, !priv->awb); ++ ret |= reg16_write(client, 0x5001, priv->red >> 8); ++ ret |= reg16_write(client, 0x5002, priv->red & 0xff); ++ ret |= reg16_write(client, 0x5003, priv->green_r >> 8); ++ ret |= reg16_write(client, 0x5004, priv->green_r & 0xff); ++ ret |= reg16_write(client, 0x5005, priv->green_b >> 8); ++ ret |= reg16_write(client, 0x5006, priv->green_b & 0xff); ++ ret |= reg16_write(client, 0x5007, priv->blue >> 8); ++ ret |= reg16_write(client, 0x5008, priv->blue & 0xff); ++ ret |= reg16_write(client, 0x5009, priv->red >> 8); ++ ret |= reg16_write(client, 0x500a, priv->red & 0xff); ++ ret |= reg16_write(client, 0x500b, priv->green_r >> 8); ++ ret |= reg16_write(client, 0x500c, priv->green_r & 0xff); ++ ret |= reg16_write(client, 0x500d, priv->green_b >> 8); ++ ret |= reg16_write(client, 0x500e, priv->green_b & 0xff); ++ ret |= reg16_write(client, 0x500f, priv->blue >> 8); ++ ret |= reg16_write(client, 0x5010, priv->blue & 0xff); ++ ret |= reg16_write(client, 0x5011, priv->red >> 8); ++ ret |= reg16_write(client, 0x5012, priv->red & 0xff); ++ ret |= reg16_write(client, 0x5013, priv->green_r >> 8); ++ ret |= reg16_write(client, 0x5014, priv->green_r & 0xff); ++ ret |= reg16_write(client, 0x5015, priv->green_b >> 8); ++ ret |= reg16_write(client, 0x5016, priv->green_b & 0xff); ++ ret |= reg16_write(client, 0x5017, priv->blue >> 8); ++ ret |= reg16_write(client, 0x5018, priv->blue & 0xff); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xeb); + break; + case V4L2_CID_HFLIP: -+ ret = reg16_write(client, 0x3516, 0x00); -+ ret |= reg16_write(client, 0x0ffc, 0x00); -+ ret |= reg16_write(client, 0x0500, ctrl->val); -+ ret |= reg16_write(client, 0x0501, 0x00); ++#if 1 ++ ret = reg16_write(client, 0xFFFD, 0x80); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, ctrl->val); ++ ret |= reg16_write(client, 0x5001, 0x00); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xdc); ++#else ++ ret = reg16_write(client, 0xFFFD, 0x80); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, 0x01); // read 0x3128 ++ ret |= reg16_write(client, 0x5001, 0x31); ++ ret |= reg16_write(client, 0x5002, 0x28); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xc1); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_read(client, 0x5000, &val); ++ val &= ~(0x1 << 0); ++ val |= (ctrl->val << 0); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, 0x00); // write 0x3128 ++ ret |= reg16_write(client, 0x5001, 0x31); ++ ret |= reg16_write(client, 0x5002, 0x28); ++ ret |= reg16_write(client, 0x5003, val); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xc1); ++ ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, 0x01); // read 0x3291 ++ ret |= reg16_write(client, 0x5001, 0x32); ++ ret |= reg16_write(client, 0x5002, 0x91); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xc1); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_read(client, 0x5000, &val); ++ val &= ~(0x1 << 1); ++ val |= (ctrl->val << 1); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, 0x00); // write 0x3291 ++ ret |= reg16_write(client, 0x5001, 0x32); ++ ret |= reg16_write(client, 0x5002, 0x91); ++ ret |= reg16_write(client, 0x5003, val); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xc1); ++ ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, 0x01); // read 0x3090 ++ ret |= reg16_write(client, 0x5001, 0x30); ++ ret |= reg16_write(client, 0x5002, 0x90); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xc1); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_read(client, 0x5000, &val); ++ val &= ~(0x1 << 2); ++ val |= (ctrl->val << 2); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, 0x00); // write 0x3090 ++ ret |= reg16_write(client, 0x5001, 0x30); ++ ret |= reg16_write(client, 0x5002, 0x90); ++ ret |= reg16_write(client, 0x5003, val); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xc1); ++#endif ++ break; ++ case V4L2_CID_VFLIP: ++#if 1 ++ ret = reg16_write(client, 0xFFFD, 0x80); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, ctrl->val); ++ ret |= reg16_write(client, 0x5001, 0x01); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xdc); ++#else ++ ret = reg16_write(client, 0xFFFD, 0x80); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, 0x01); // read 0x3128 ++ ret |= reg16_write(client, 0x5001, 0x31); ++ ret |= reg16_write(client, 0x5002, 0x28); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xc1); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_read(client, 0x5000, &val); ++ val &= ~(0x1 << 1); ++ val |= (ctrl->val << 1); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, 0x00); // write 0x3128 ++ ret |= reg16_write(client, 0x5001, 0x31); ++ ret |= reg16_write(client, 0x5002, 0x28); ++ ret |= reg16_write(client, 0x5003, val); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xc1); ++ ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, 0x01); // read 0x3291 ++ ret |= reg16_write(client, 0x5001, 0x32); ++ ret |= reg16_write(client, 0x5002, 0x91); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xc1); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_read(client, 0x5000, &val); ++ val &= ~(0x1 << 2); ++ val |= (ctrl->val << 2); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, 0x00); // write 0x3291 ++ ret |= reg16_write(client, 0x5001, 0x32); ++ ret |= reg16_write(client, 0x5002, 0x91); ++ ret |= reg16_write(client, 0x5003, val); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xc1); ++ ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, 0x01); // read 0x3090 ++ ret |= reg16_write(client, 0x5001, 0x30); ++ ret |= reg16_write(client, 0x5002, 0x90); ++ ret |= reg16_write(client, 0xFFFE, 0x80); + usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x30C0, 0xdc); -+ ret |= reg16_write(client, 0x3516, 0x01); -+ break; -+ case V4L2_CID_VFLIP: -+ ret = reg16_write(client, 0x3516, 0x00); -+ ret |= reg16_write(client, 0x0ffc, 0x00); -+ ret |= reg16_write(client, 0x0500, ctrl->val); -+ ret |= reg16_write(client, 0x0501, 0x01); ++ ret |= reg16_write(client, 0x00C0, 0xc1); ++ ret |= reg16_write(client, 0xFFFE, 0x19); + usleep_range(100, 150); /* wait 100 us */ -+ ret |= reg16_write(client, 0x30C0, 0xdc); -+ ret |= reg16_write(client, 0x3516, 0x01); ++ ret |= reg16_read(client, 0x5000, &val); ++ val &= ~(0x1 << 3); ++ val |= (ctrl->val << 3); ++ ret |= reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x5000, 0x00); // write 0x3090 ++ ret |= reg16_write(client, 0x5001, 0x30); ++ ret |= reg16_write(client, 0x5002, 0x90); ++ ret |= reg16_write(client, 0x5003, val); ++ ret |= reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x00C0, 0xc1); ++#endif + break; + case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: + ret = 0; @@ -6214,142 +5896,198 @@ index 0000000..6dc0675 + return ret; +} + -+static const struct v4l2_ctrl_ops ov495_ctrl_ops = { -+ .s_ctrl = ov495_s_ctrl, ++static const struct v4l2_ctrl_ops ov490_ctrl_ops = { ++ .s_ctrl = ov490_s_ctrl, +}; + -+static struct v4l2_subdev_video_ops ov495_video_ops = { -+ .s_stream = ov495_s_stream, -+ .g_mbus_config = ov495_g_mbus_config, ++static struct v4l2_subdev_video_ops ov490_video_ops = { ++ .s_stream = ov490_s_stream, ++ .g_mbus_config = ov490_g_mbus_config, +}; + -+static const struct v4l2_subdev_pad_ops ov495_subdev_pad_ops = { -+ .get_edid = ov495_get_edid, -+ .enum_mbus_code = ov495_enum_mbus_code, -+ .get_selection = ov495_get_selection, -+ .set_selection = ov495_set_selection, -+ .get_fmt = ov495_get_fmt, -+ .set_fmt = ov495_set_fmt, ++static const struct v4l2_subdev_pad_ops ov490_subdev_pad_ops = { ++ .get_edid = ov490_get_edid, ++ .enum_mbus_code = ov490_enum_mbus_code, ++ .get_selection = ov490_get_selection, ++ .set_selection = ov490_set_selection, ++ .get_fmt = ov490_get_fmt, ++ .set_fmt = ov490_set_fmt, +}; + -+static struct v4l2_subdev_ops ov495_subdev_ops = { -+ .core = &ov495_core_ops, -+ .video = &ov495_video_ops, -+ .pad = &ov495_subdev_pad_ops, ++static struct v4l2_subdev_ops ov490_subdev_ops = { ++ .core = &ov490_core_ops, ++ .video = &ov490_video_ops, ++ .pad = &ov490_subdev_pad_ops, +}; + -+static void ov495_otp_id_read(struct i2c_client *client) ++static void ov490_otp_id_read(struct i2c_client *client) +{ -+ struct ov495_priv *priv = to_ov495(client); ++ struct ov490_priv *priv = to_ov490(client); + int i; ++ int otp_bank0_allzero = 1; + +#if 0 -+ /* read camera id from ov495 OTP memory */ ++ /* read camera id from ov490 OTP memory */ + reg16_write(client, 0xFFFD, 0x80); -+ reg16_write(client, 0xFFFE, 0x20); ++ reg16_write(client, 0xFFFE, 0x28); + usleep_range(100, 150); /* wait 100 us */ -+ reg16_write(client, 0x7384, 0x40); /* manual mode, bank#0 */ -+ reg16_write(client, 0x7381, 1); /* start OTP read */ ++ reg16_write(client, 0xE084, 0x40); /* manual mode, bank#0 */ ++ reg16_write(client, 0xE081, 1); /* start OTP read */ + + usleep_range(25000, 26000); /* wait 25 ms */ + + for (i = 0; i < 6; i++) -+ reg16_read(client, 0x7300 + i + 4, &priv->id[i]); ++ reg16_read(client, 0xe000 + i + 4, &priv->id[i]); +#else -+ /* read camera id from ov2775 OTP memory */ -+ reg16_write(client, 0x3516, 0x00); /* unlock write */ -+ reg16_write(client, 0x0FFC, 0); -+ reg16_write(client, 0x0500, 0x00); /* write 0x34a1 -> 1 */ -+ reg16_write(client, 0x0501, 0x34); -+ reg16_write(client, 0x0502, 0xa1); -+ reg16_write(client, 0x0503, 1); -+ reg16_write(client, 0x30C0, 0xc1); -+ ++ /* read camera id from ov10640 OTP memory */ ++ ov490_ov10640_write(client, 0x349C, 1); + usleep_range(25000, 25500); /* wait 25 ms */ + + for (i = 0; i < 6; i++) { -+ reg16_write(client, 0x3516, 0x00); /* unlock write */ -+ reg16_write(client, 0x0500, 0x01); /* read (0x7a00 + i) */ -+ reg16_write(client, 0x0501, 0x7a); -+ reg16_write(client, 0x0502, 0x00 + i + (i < 3 ? 11 : 3)); /* take bytes 11,12,13,6,7,8 */ -+ reg16_write(client, 0x30C0, 0xc1); -+ usleep_range(1000, 1500); /* wait 1 ms */ -+ reg16_read(client, 0x0500, &priv->id[i]); ++ /* first 6 bytes are equal on all ov10640 */ ++ priv->id[i] = ov490_ov10640_read(client, 0x349e + i + 6); ++ if (priv->id[i]) ++ otp_bank0_allzero = 0; ++ } ++ ++ if (otp_bank0_allzero) { ++ ov490_ov10640_write(client, 0x3495, 0x41); /* bank#1 */ ++ ov490_ov10640_write(client, 0x349C, 1); ++ usleep_range(25000, 25500); /* wait 25 ms */ ++ ++ for (i = 0; i < 6; i++) ++ priv->id[i] = ov490_ov10640_read(client, 0x34ae + i); + } +#endif +} + -+static ssize_t ov495_otp_id_show(struct device *dev, ++static ssize_t ov490_otp_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev)); + struct i2c_client *client = v4l2_get_subdevdata(sd); -+ struct ov495_priv *priv = to_ov495(client); ++ struct ov490_priv *priv = to_ov490(client); + + return snprintf(buf, 32, "%02x:%02x:%02x:%02x:%02x:%02x\n", + priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); +} + -+static DEVICE_ATTR(otp_id_ov495, S_IRUGO, ov495_otp_id_show, NULL); ++static DEVICE_ATTR(otp_id_ov490, S_IRUGO, ov490_otp_id_show, NULL); + -+static int ov495_initialize(struct i2c_client *client) ++static int ov490_initialize(struct i2c_client *client) +{ -+ struct ov495_priv *priv = to_ov495(client); ++ struct ov490_priv *priv = to_ov490(client); ++ u8 val = 0; + u8 pid = 0, ver = 0; -+ int ret = 0; ++ int ret = 0, timeout, retry_timeout = 3; ++ ++ if (priv->is_fixed_sensor) { ++ dev_info(&client->dev, "ov490/ov10640 fixed-sensor res %dx%d\n", priv->max_width, priv->max_height); ++ return 0; ++ } ++ ++ ov490_s_port(client, 1); + + /* check and show product ID and manufacturer ID */ + reg16_write(client, 0xFFFD, 0x80); + reg16_write(client, 0xFFFE, 0x80); + usleep_range(100, 150); /* wait 100 us */ -+ reg16_read(client, OV495_PID, &pid); -+ reg16_read(client, OV495_VER, &ver); ++ reg16_read(client, OV490_PID, &pid); ++ reg16_read(client, OV490_VER, &ver); + -+ if (OV495_VERSION(pid, ver) != OV495_VERSION_REG) { -+ dev_err(&client->dev, "Product ID error %x:%x\n", pid, ver); ++ if (OV490_VERSION(pid, ver) != OV490_VERSION_REG) { ++ dev_dbg(&client->dev, "Product ID error %x:%x\n", pid, ver); + ret = -ENODEV; + goto err; + } + -+ if (unlikely(force_conf_link)) ++ if (unlikely(conf_link)) + goto out; + -+#if 0 ++again: ++ /* Check if firmware booted by reading stream-on status */ ++ reg16_write(client, 0xFFFD, 0x80); ++ reg16_write(client, 0xFFFE, 0x29); ++ usleep_range(100, 150); /* wait 100 us */ ++ for (timeout = 300; timeout > 0; timeout--) { ++ reg16_read(client, 0xd000, &val); ++ if (val == 0x0c) ++ break; ++ mdelay(1); ++ } ++ ++ /* wait firmware apps started by reading OV10640 ID */ ++ for (;timeout > 0; timeout--) { ++ reg16_write(client, 0xFFFD, 0x80); ++ reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(100, 150); /* wait 100 us */ ++ reg16_write(client, 0x5000, 0x01); ++ reg16_write(client, 0x5001, 0x30); ++ reg16_write(client, 0x5002, 0x0a); ++ reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ reg16_write(client, 0xC0, 0xc1); ++ reg16_write(client, 0xFFFE, 0x19); ++ usleep_range(1000, 1500); /* wait 1 ms */ ++ reg16_read(client, 0x5000, &val); ++ if (val == 0xa6) ++ break; ++ mdelay(1); ++ } ++ ++ if (!timeout) { ++ dev_err(&client->dev, "Timeout firmware boot wait, retrying\n"); ++ /* reset OV10640 using RESETB pin controlled by OV490 GPIO0 */ ++ reg16_write(client, 0xFFFD, 0x80); ++ reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ reg16_write(client, 0x0050, 0x01); ++ reg16_write(client, 0x0054, 0x01); ++ reg16_write(client, 0x0058, 0x00); ++ mdelay(10); ++ reg16_write(client, 0x0058, 0x01); ++ /* reset OV490 using RESETB pin controlled by serializer */ ++ ov490_reset(client); ++ if (retry_timeout--) ++ goto again; ++ } ++ + /* read resolution used by current firmware */ + reg16_write(client, 0xFFFD, 0x80); + reg16_write(client, 0xFFFE, 0x82); + usleep_range(100, 150); /* wait 100 us */ -+ reg16_read(client, OV495_ISP_HSIZE_HIGH, &val); ++ reg16_read(client, OV490_ISP_HSIZE_HIGH, &val); + priv->max_width = val; -+ reg16_read(client, OV495_ISP_HSIZE_LOW, &val); ++ reg16_read(client, OV490_ISP_HSIZE_LOW, &val); + priv->max_width = (priv->max_width << 8) | val; -+ reg16_read(client, OV495_ISP_VSIZE_HIGH, &val); ++ reg16_read(client, OV490_ISP_VSIZE_HIGH, &val); + priv->max_height = val; -+ reg16_read(client, OV495_ISP_VSIZE_LOW, &val); ++ reg16_read(client, OV490_ISP_VSIZE_LOW, &val); + priv->max_height = (priv->max_height << 8) | val; -+#else -+ priv->max_width = 1920; -+ priv->max_height = 1080; -+#endif -+ -+ /* set virtual channel */ -+ ov495_regs_wizard[3].val = 0x1e | (priv->port << 6); + /* Program wizard registers */ -+ ov495_set_regs(client, ov495_regs_wizard, ARRAY_SIZE(ov495_regs_wizard)); ++ ov490_set_regs(client, ov490_regs_wizard, ARRAY_SIZE(ov490_regs_wizard)); ++ /* Set DVP bit swap */ ++ reg16_write(client, 0xFFFD, 0x80); ++ reg16_write(client, 0xFFFE, 0x28); ++ usleep_range(100, 150); /* wait 100 us */ ++ reg16_write(client, 0x6009, priv->dvp_order << 4); + /* Read OTP IDs */ -+ ov495_otp_id_read(client); ++ ov490_otp_id_read(client); + +out: -+ dev_info(&client->dev, "ov495/ov2775 PID %x%x, res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n", ++ dev_info(&client->dev, "ov490/ov10640 PID %x%x, res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n", + pid, ver, priv->max_width, priv->max_height, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); +err: ++ ov490_s_port(client, 0); ++ + return ret; +} + -+static int ov495_parse_dt(struct device_node *np, struct ov495_priv *priv) ++static int ov490_parse_dt(struct device_node *np, struct ov490_priv *priv) +{ + struct i2c_client *client = v4l2_get_subdevdata(&priv->sd); + int i; ++ const char *fixed_sensor; + struct device_node *endpoint = NULL, *rendpoint = NULL; + int tmp_addr = 0; + @@ -6360,63 +6098,88 @@ index 0000000..6dc0675 + + of_node_put(endpoint); + ++ of_property_read_u32(endpoint, "dvp-order", &priv->dvp_order); ++ + rendpoint = of_parse_phandle(endpoint, "remote-endpoint", 0); + if (!rendpoint) + continue; + -+ if (!of_property_read_u32(rendpoint, "ti9x3-addr", &priv->ti9x3_addr) && -+ !of_property_match_string(rendpoint->parent->parent, "compatible", "ti,ti964-ti9x3") && -+ !of_property_read_u32(rendpoint->parent->parent, "reg", &priv->ti960_addr) && -+ !kstrtouint(strrchr(rendpoint->full_name, '@') + 1, 0, &priv->port)) ++ if (!of_property_read_u32(rendpoint, "max9271-addr", &priv->max9271_addr) && ++ !of_property_read_u32(rendpoint->parent->parent, "reg", &priv->max9286_addr) && ++ !kstrtouint(strrchr(rendpoint->full_name, '@') + 1, 0, &priv->port)) { ++ if (of_property_read_u32(rendpoint->parent->parent, "maxim,resetb-gpio", &priv->gpio_resetb)) { ++ priv->gpio_resetb = -1; ++ } else { ++ if (of_property_read_bool(rendpoint->parent->parent, "maxim,resetb-active-high")) ++ priv->active_low_resetb = false; ++ else ++ priv->active_low_resetb = true; ++ } + break; ++ } + + if (!of_property_read_u32(rendpoint, "ti9x3-addr", &priv->ti9x3_addr) && -+ !of_property_match_string(rendpoint->parent->parent, "compatible", "ti,ti954-ti9x3") && -+ !of_property_read_u32(rendpoint->parent->parent, "reg", &priv->ti954_addr) && ++ !of_property_match_string(rendpoint->parent->parent, "compatible", "ti,ti9x4") && ++ !of_property_read_u32(rendpoint->parent->parent, "reg", &priv->ti9x4_addr) && + !kstrtouint(strrchr(rendpoint->full_name, '@') + 1, 0, &priv->port)) + break; + } + -+ if (!priv->ti960_addr && !priv->ti954_addr) { -+ dev_err(&client->dev, "deserializer does not present for OV495\n"); ++ if (!priv->max9286_addr && !priv->ti9x4_addr) { ++ dev_err(&client->dev, "deserializer does not present for OV490\n"); + return -EINVAL; + } + ++ ov490_s_port(client, 1); ++ + /* setup I2C translator address */ + tmp_addr = client->addr; -+ if (priv->ti960_addr) { -+ client->addr = priv->ti960_addr; /* Deserializer I2C address */ ++ if (priv->max9286_addr) { ++ client->addr = priv->max9271_addr; /* Serializer I2C address */ + -+ reg8_write(client, 0x4c, (priv->port << 4) | (1 << priv->port)); /* Select RX port number */ ++ reg8_write(client, 0x09, tmp_addr << 1); /* Sensor translated I2C address */ ++ reg8_write(client, 0x0A, OV490_I2C_ADDR << 1); /* Sensor native I2C address */ + usleep_range(2000, 2500); /* wait 2ms */ -+ reg8_write(client, 0x65, tmp_addr << 1); /* Sensor translated I2C address */ -+ reg8_write(client, 0x5d, OV495_I2C_ADDR << 1); /* Sensor native I2C address */ -+ -+ reg8_write(client, 0x6e, 0x9a); /* GPIO0 - fsin, GPIO1 - resetb */ -+ /* TODO: why too long? move logic to workqueue? */ -+ mdelay(350); /* time needed to boot all sensor IPs */ -+ } -+ if (priv->ti954_addr) { -+ client->addr = priv->ti954_addr; /* Deserializer I2C address */ ++ }; ++ if (priv->ti9x4_addr) { ++ client->addr = priv->ti9x4_addr; /* Deserializer I2C address */ + + reg8_write(client, 0x4c, (priv->port << 4) | (1 << priv->port)); /* Select RX port number */ + usleep_range(2000, 2500); /* wait 2ms */ + reg8_write(client, 0x65, tmp_addr << 1); /* Sensor translated I2C address */ -+ reg8_write(client, 0x5d, OV495_I2C_ADDR << 1); /* Sensor native I2C address */ ++ reg8_write(client, 0x5d, OV490_I2C_ADDR << 1); /* Sensor native I2C address */ + + reg8_write(client, 0x6e, 0x9a); /* GPIO0 - fsin, GPIO1 - resetb */ -+ /* TODO: why too long? move logic to workqueue? */ -+ mdelay(350); /* time needed to boot all sensor IPs */ + } + client->addr = tmp_addr; + ++ if (!of_property_read_string(np, "maxim,fixed-sensor", &fixed_sensor) && ++ strcmp(fixed_sensor, "ov490") == 0) { ++ if (of_property_read_u32(np, "maxim,width", &priv->max_width)) ++ priv->max_width = 1280; ++ ++ if (of_property_read_u32(np, "maxim,height", &priv->max_height)) ++ priv->max_height = 966; ++ ++ priv->is_fixed_sensor = true; ++ } ++ ++ /* module params override dts */ ++ if (dvp_order) ++ priv->dvp_order = dvp_order; ++ if (max_width && max_height) { ++ priv->max_width = max_width; ++ priv->max_height = max_height; ++ priv->is_fixed_sensor = true; ++ } ++ + return 0; +} + -+static int ov495_probe(struct i2c_client *client, ++static int ov490_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ -+ struct ov495_priv *priv; ++ struct ov490_priv *priv; + struct v4l2_ctrl *ctrl; + int ret; + @@ -6424,36 +6187,47 @@ index 0000000..6dc0675 + if (!priv) + return -ENOMEM; + -+ v4l2_i2c_subdev_init(&priv->sd, client, &ov495_subdev_ops); ++ v4l2_i2c_subdev_init(&priv->sd, client, &ov490_subdev_ops); + priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; + + priv->exposure = 0x100; + priv->gain = 0x100; + priv->autogain = 1; ++ priv->red = 0x400; ++ priv->blue = 0x400; ++ priv->green_r = priv->red / 2; ++ priv->green_b = priv->blue / 2; ++ priv->awb = 1; + v4l2_ctrl_handler_init(&priv->hdl, 4); -+ v4l2_ctrl_new_std(&priv->hdl, &ov495_ctrl_ops, ++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 16, 1, 7); -+ v4l2_ctrl_new_std(&priv->hdl, &ov495_ctrl_ops, ++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, + V4L2_CID_CONTRAST, 0, 16, 1, 7); -+ v4l2_ctrl_new_std(&priv->hdl, &ov495_ctrl_ops, ++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, + V4L2_CID_SATURATION, 0, 7, 1, 2); -+ v4l2_ctrl_new_std(&priv->hdl, &ov495_ctrl_ops, ++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, + V4L2_CID_HUE, 0, 23, 1, 12); -+ v4l2_ctrl_new_std(&priv->hdl, &ov495_ctrl_ops, ++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, + V4L2_CID_GAMMA, -128, 128, 1, 0); -+ v4l2_ctrl_new_std(&priv->hdl, &ov495_ctrl_ops, ++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, + V4L2_CID_SHARPNESS, 0, 10, 1, 3); -+ v4l2_ctrl_new_std(&priv->hdl, &ov495_ctrl_ops, ++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, + V4L2_CID_AUTOGAIN, 0, 1, 1, priv->autogain); -+ v4l2_ctrl_new_std(&priv->hdl, &ov495_ctrl_ops, ++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, + V4L2_CID_GAIN, 0, 0xffff, 1, priv->gain); -+ v4l2_ctrl_new_std(&priv->hdl, &ov495_ctrl_ops, ++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, + V4L2_CID_EXPOSURE, 0, 0xffff, 1, priv->exposure); -+ v4l2_ctrl_new_std(&priv->hdl, &ov495_ctrl_ops, -+ V4L2_CID_HFLIP, 0, 1, 1, 0); -+ v4l2_ctrl_new_std(&priv->hdl, &ov495_ctrl_ops, ++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, ++ V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, priv->autogain); ++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, ++ V4L2_CID_RED_BALANCE, 2, 0xf, 1, priv->red >> 8); ++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, ++ V4L2_CID_BLUE_BALANCE, 2, 0xf, 1, priv->blue >> 8); ++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 1); ++ v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); -+ ctrl = v4l2_ctrl_new_std(&priv->hdl, &ov495_ctrl_ops, ++ ctrl = v4l2_ctrl_new_std(&priv->hdl, &ov490_ctrl_ops, + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 9); + if (ctrl) + ctrl->flags &= ~V4L2_CTRL_FLAG_READ_ONLY; @@ -6471,11 +6245,11 @@ index 0000000..6dc0675 + if (ret < 0) + goto cleanup; + -+ ret = ov495_parse_dt(client->dev.of_node, priv); ++ ret = ov490_parse_dt(client->dev.of_node, priv); + if (ret) + goto cleanup; + -+ ret = ov495_initialize(client); ++ ret = ov490_initialize(client); + if (ret < 0) + goto cleanup; + @@ -6488,7 +6262,7 @@ index 0000000..6dc0675 + if (ret) + goto cleanup; + -+ if (device_create_file(&client->dev, &dev_attr_otp_id_ov495) != 0) { ++ if (device_create_file(&client->dev, &dev_attr_otp_id_ov490) != 0) { + dev_err(&client->dev, "sysfs otp_id entry creation failed\n"); + goto cleanup; + } @@ -6501,18 +6275,18 @@ index 0000000..6dc0675 + media_entity_cleanup(&priv->sd.entity); + v4l2_ctrl_handler_free(&priv->hdl); + v4l2_device_unregister_subdev(&priv->sd); -+#ifdef CONFIG_SOC_CAMERA_OV495_OV2775 ++#ifdef CONFIG_SOC_CAMERA_OV490_OV10640 + v4l_err(client, "failed to probe @ 0x%02x (%s)\n", + client->addr, client->adapter->name); +#endif + return ret; +} + -+static int ov495_remove(struct i2c_client *client) ++static int ov490_remove(struct i2c_client *client) +{ -+ struct ov495_priv *priv = i2c_get_clientdata(client); ++ struct ov490_priv *priv = i2c_get_clientdata(client); + -+ device_remove_file(&client->dev, &dev_attr_otp_id_ov495); ++ device_remove_file(&client->dev, &dev_attr_otp_id_ov490); + v4l2_async_unregister_subdev(&priv->sd); + media_entity_cleanup(&priv->sd.entity); + v4l2_ctrl_handler_free(&priv->hdl); @@ -6521,45 +6295,45 @@ index 0000000..6dc0675 + return 0; +} + -+#ifdef CONFIG_SOC_CAMERA_OV495_OV2775 -+static const struct i2c_device_id ov495_id[] = { -+ { "ov495-ov2775", 0 }, ++#ifdef CONFIG_SOC_CAMERA_OV490_OV10640 ++static const struct i2c_device_id ov490_id[] = { ++ { "ov490-ov10640", 0 }, + { } +}; -+MODULE_DEVICE_TABLE(i2c, ov495_id); ++MODULE_DEVICE_TABLE(i2c, ov490_id); + -+static const struct of_device_id ov495_of_ids[] = { -+ { .compatible = "ovti,ov495-ov2775", }, ++static const struct of_device_id ov490_of_ids[] = { ++ { .compatible = "ovti,ov490-ov10640", }, + { } +}; -+MODULE_DEVICE_TABLE(of, ov495_of_ids); ++MODULE_DEVICE_TABLE(of, ov490_of_ids); + -+static struct i2c_driver ov495_i2c_driver = { ++static struct i2c_driver ov490_i2c_driver = { + .driver = { -+ .name = "ov495-ov2775", -+ .of_match_table = ov495_of_ids, ++ .name = "ov490-ov10640", ++ .of_match_table = ov490_of_ids, + }, -+ .probe = ov495_probe, -+ .remove = ov495_remove, -+ .id_table = ov495_id, ++ .probe = ov490_probe, ++ .remove = ov490_remove, ++ .id_table = ov490_id, +}; + -+module_i2c_driver(ov495_i2c_driver); ++module_i2c_driver(ov490_i2c_driver); + -+MODULE_DESCRIPTION("SoC Camera driver for OV495-OV2775"); ++MODULE_DESCRIPTION("SoC Camera driver for OV490-OV10640"); +MODULE_AUTHOR("Vladimir Barinov"); +MODULE_LICENSE("GPL"); +#endif -diff --git a/drivers/media/i2c/soc_camera/ov495_ov2775.h b/drivers/media/i2c/soc_camera/ov495_ov2775.h +diff --git a/drivers/media/i2c/soc_camera/ov490_ov10640.h b/drivers/media/i2c/soc_camera/ov490_ov10640.h new file mode 100644 -index 0000000..3f53689 +index 0000000..b22e93e --- /dev/null -+++ b/drivers/media/i2c/soc_camera/ov495_ov2775.h -@@ -0,0 +1,23 @@ ++++ b/drivers/media/i2c/soc_camera/ov490_ov10640.h +@@ -0,0 +1,102 @@ +/* -+ * OmniVision ov495-ov2775 sensor camera wizard 1280x1080@30/UYVY/BT601/8bit ++ * OmniVision ov490-ov10640 sensor camera wizard 1280x1080@30/UYVY/BT601/8bit + * -+ * Copyright (C) 2017 Cogent Embedded, Inc. ++ * Copyright (C) 2016-2017 Cogent Embedded, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the @@ -6567,26 +6341,105 @@ index 0000000..3f53689 + * option) any later version. + */ + -+struct ov495_reg { ++//#define OV490_DISPLAY_PATTERN ++ ++struct ov490_reg { + u16 reg; + u8 val; +}; + -+static struct ov495_reg ov495_regs_wizard[] = { -+{0x3516, 0x00}, /* unlock write */ -+{0xFFFD, 0x80}, -+{0xFFFE, 0x20}, -+{0x8017, 0x1e | (0 << 6)}, -+{0x7c10, 0x01}, /* UYVY */ ++static const struct ov490_reg ov490_regs_wizard[] = { ++/* The following registers should match firmware */ ++{0xfffd, 0x80}, ++{0xfffe, 0x82}, ++{0x0071, 0x11}, ++{0x0075, 0x11}, ++{0xfffe, 0x29}, ++{0x6010, 0x01}, ++/* ov490 EMB line disable in YUV and RAW data, NOTE: EMB line is still used in ISP and sensor */ ++{0xe000, 0x14}, ++#if 0 /* do not disable EMB line in ISP! */ ++{0x4017, 0x00}, ++#endif ++{0xfffe, 0x28}, ++{0x6000, 0x04}, ++{0x6004, 0x00}, ++{0x6008, 0x00}, // PCLK polarity - useless due to silicon bug -> use 0x808000bb register ++{0xfffe, 0x80}, ++{0x0091, 0x00}, ++{0x00bb, 0x1d}, // bit[3]=0 - PCLK polarity workaround ++/* ov10640 EMB line disable */ ++#if 0 /* do not disable EMB line in sensor! */ ++{0xfffe, 0x19}, ++{0x5000, 0x00}, ++{0x5001, 0x30}, ++{0x5002, 0x91}, ++{0x5003, 0x08}, ++{0xfffe, 0x80}, ++{0x00c0, 0xc1}, ++#endif ++/* Ov490 FSIN: app_fsin_from_fsync */ ++{0xfffe, 0x85}, ++{0x0008, 0x00}, ++{0x0009, 0x01}, ++{0x000A, 0x05}, // fsin0 src ++{0x000B, 0x00}, ++{0x0030, 0x02}, // fsin0_delay ++{0x0031, 0x00}, ++{0x0032, 0x00}, ++{0x0033, 0x00}, ++{0x0038, 0x02}, // fsin1_delay ++{0x0039, 0x00}, ++{0x003A, 0x00}, ++{0x003B, 0x00}, ++{0x0070, 0x2C}, // fsin0_length ++{0x0071, 0x01}, ++{0x0072, 0x00}, ++{0x0073, 0x00}, ++{0x0074, 0x64}, // fsin1_length ++{0x0075, 0x00}, ++{0x0076, 0x00}, ++{0x0077, 0x00}, ++{0x0000, 0x14}, ++{0x0001, 0x00}, ++{0x0002, 0x00}, ++{0x0003, 0x00}, ++{0x0004, 0x32}, // load fsin0,load fsin1,load other, it will be cleared automatically. ++{0x0005, 0x00}, ++{0x0006, 0x00}, ++{0x0007, 0x00}, ++{0xfffe, 0x80}, ++{0x0081, 0x00}, // 03;SENSOR FSIN ++/* ov10640 FSIN */ ++{0xfffe, 0x19}, ++{0x5000, 0x00}, ++{0x5001, 0x30}, ++{0x5002, 0x8c}, ++{0x5003, 0xb2}, ++{0xfffe, 0x80}, ++{0x00c0, 0xc1}, ++/* ov10640 HFLIP=1 by default */ ++{0xfffe, 0x19}, ++{0x5000, 0x01}, ++{0x5001, 0x00}, ++{0xfffe, 0x80}, ++{0x00c0, 0xdc}, ++#ifdef OV490_DISPLAY_PATTERN ++{0xfffd, 0x80}, ++{0xfffe, 0x19}, ++{0x5000, 0x02}, ++{0xfffe, 0x80}, ++{0x00c0, 0xd6}, ++#endif +}; -diff --git a/drivers/media/i2c/soc_camera/ti954_ti9x3.c b/drivers/media/i2c/soc_camera/ti954_ti9x3.c +diff --git a/drivers/media/i2c/soc_camera/ov495_ov2775.c b/drivers/media/i2c/soc_camera/ov495_ov2775.c new file mode 100644 -index 0000000..ff84128 +index 0000000..e53c482 --- /dev/null -+++ b/drivers/media/i2c/soc_camera/ti954_ti9x3.c -@@ -0,0 +1,439 @@ ++++ b/drivers/media/i2c/soc_camera/ov495_ov2775.c +@@ -0,0 +1,639 @@ +/* -+ * TI ti954-(ti913/ti953) FPDLinkIII driver ++ * OmniVision ov495-ov2775 sensor camera driver + * + * Copyright (C) 2017 Cogent Embedded, Inc. + * @@ -6596,310 +6449,454 @@ index 0000000..ff84128 + * option) any later version. + */ + -+#include -+#include -+#include -+#include -+#include -+#include -+#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "ov495_ov2775.h" ++ ++#define OV495_I2C_ADDR 0x24 ++ ++#define OV495_PID 0x300a ++#define OV495_VER 0x300b ++#define OV495_VERSION_REG 0x0495 ++#define OV495_VERSION(pid, ver) (((pid) << 8) | ((ver) & 0xff)) ++ ++#define OV495_ISP_HSIZE_LOW 0x60 ++#define OV495_ISP_HSIZE_HIGH 0x61 ++#define OV495_ISP_VSIZE_LOW 0x62 ++#define OV495_ISP_VSIZE_HIGH 0x63 ++ ++struct ov495_priv { ++ struct v4l2_subdev sd; ++ struct v4l2_ctrl_handler hdl; ++ struct media_pad pad; ++ struct v4l2_rect rect; ++ int max_width; ++ int max_height; ++ int init_complete; ++ u8 id[6]; ++ int exposure; ++ int gain; ++ int autogain; ++ /* serializers */ ++ int max9286_addr; ++ int max9271_addr; ++ int ti9x4_addr; ++ int ti9x3_addr; ++ int port; ++ int gpio_resetb; ++ int gpio_fsin; ++ ++}; + -+#include -+#include -+#include -+#include ++static int force_conf_link; + -+#include "ti9x4_ti9x3.h" ++static __init int ov495_force_conf_link(char *str) ++{ ++ /* force configuration link */ ++ /* used only if robust firmware flashing required (f.e. recovery) */ ++ force_conf_link = 1; ++ return 0; ++} ++early_param("force_conf_link", ov495_force_conf_link); + -+struct ti954_ti9x3_priv { -+ struct v4l2_subdev sd[4]; -+ struct device_node *sd_of_node[4]; -+ int des_addr; -+ int links; -+ int lanes; -+ int csi_rate; -+ const char *forwarding_mode; -+ const char *cable_mode; -+ int poc_delay; -+ atomic_t use_count; -+ struct i2c_client *client; -+ int ti9x3_addr_map[4]; -+ char chip_id[6]; -+ struct regulator *poc_supply[4]; /* PoC power supply */ -+ int xtal_gpio; -+}; ++static inline struct ov495_priv *to_ov495(const struct i2c_client *client) ++{ ++ return container_of(i2c_get_clientdata(client), struct ov495_priv, sd); ++} + -+static int indirect_write(struct i2c_client *client, unsigned int page, u8 reg, u8 val) ++static int ov495_set_regs(struct i2c_client *client, ++ const struct ov495_reg *regs, int nr_regs) +{ -+ if (page > 7) -+ return -EINVAL; ++ int i; + -+ reg8_write(client, 0xb0, page << 2); -+ reg8_write(client, 0xb1, reg); -+ reg8_write(client, 0xb2, val); ++ for (i = 0; i < nr_regs; i++) { ++ if (reg16_write(client, regs[i].reg, regs[i].val)) { ++ usleep_range(100, 150); /* wait 100 us */ ++ reg16_write(client, regs[i].reg, regs[i].val); ++ } ++ } + + return 0; +} + -+#if 0 -+static int indirect_read(struct i2c_client *client, unsigned int page, u8 reg, u8 *val) ++static int ov495_s_stream(struct v4l2_subdev *sd, int enable) +{ -+ if (page > 7) ++ return 0; ++} ++ ++static int ov495_get_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) ++{ ++ struct v4l2_mbus_framefmt *mf = &format->format; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov495_priv *priv = to_ov495(client); ++ ++ if (format->pad) + return -EINVAL; + -+ reg8_write(client, 0xb0, page << 2); -+ reg8_write(client, 0xb1, reg); -+ reg8_read(client, 0xb2, val); ++ mf->width = priv->rect.width; ++ mf->height = priv->rect.height; ++ mf->code = MEDIA_BUS_FMT_YUYV8_2X8; ++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M; ++ mf->field = V4L2_FIELD_NONE; + + return 0; +} -+#endif -+ -+static int poc_delay; -+module_param(poc_delay, int, 0644); -+MODULE_PARM_DESC(poc_delay, " Delay in ms after POC enable (default: 0 ms) */"); + -+static void ti954_ti9x3_read_chipid(struct i2c_client *client) ++static int ov495_set_fmt(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_format *format) +{ -+ struct ti954_ti9x3_priv *priv = i2c_get_clientdata(client); ++ struct v4l2_mbus_framefmt *mf = &format->format; + -+ /* Chip ID */ -+ reg8_read(client, 0xf1, &priv->chip_id[0]); -+ reg8_read(client, 0xf2, &priv->chip_id[1]); -+ reg8_read(client, 0xf3, &priv->chip_id[2]); -+ reg8_read(client, 0xf4, &priv->chip_id[3]); -+ reg8_read(client, 0xf5, &priv->chip_id[4]); -+ priv->chip_id[5] = '\0'; ++ mf->code = MEDIA_BUS_FMT_YUYV8_2X8; ++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M; ++ mf->field = V4L2_FIELD_NONE; ++ ++ if (format->which == V4L2_SUBDEV_FORMAT_TRY) ++ cfg->try_fmt = *mf; ++ ++ return 0; +} + -+static void ti954_ti9x3_initial_setup(struct i2c_client *client) ++static int ov495_enum_mbus_code(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_mbus_code_enum *code) +{ -+ struct ti954_ti9x3_priv *priv = i2c_get_clientdata(client); -+ -+ /* Initial setup */ -+ client->addr = priv->des_addr; /* TI954 I2C */ -+ reg8_write(client, 0x08, 0x1c); /* I2C glitch filter depth */ -+ reg8_write(client, 0x0a, 0x79); /* I2C high pulse width */ -+ reg8_write(client, 0x0b, 0x79); /* I2C low pulse width */ -+ reg8_write(client, 0x0d, 0xb9); /* VDDIO 3.3V */ -+ switch (priv->csi_rate) { -+ case 1600: /* REFCLK = 25MHZ */ -+ case 1450: /* REFCLK = 22.5MHZ */ -+ reg8_write(client, 0x1f, 0x00); /* CSI rate 1.5/1.6Gbps */ -+ break; -+ case 800: /* REFCLK = 25MHZ */ -+ reg8_write(client, 0x1f, 0x02); /* CSI rate 800Mbps */ -+ break; -+ case 400: /* REFCLK = 25MHZ */ -+ reg8_write(client, 0x1f, 0x03); /* CSI rate 400Mbps */ -+ break; -+ default: -+ dev_err(&client->dev, "unsupported CSI rate %d\n", priv->csi_rate); -+ } ++ if (code->pad || code->index > 0) ++ return -EINVAL; + -+ if (strcmp(priv->forwarding_mode, "round-robin") == 0) { -+ reg8_write(client, 0x21, 0x01); /* Round Robin forwarding enable */ -+ } else if (strcmp(priv->forwarding_mode, "synchronized") == 0) { -+ reg8_write(client, 0x21, 0x44); /* Basic Syncronized forwarding enable (FrameSync must be enabled!!) */ -+ } ++ code->code = MEDIA_BUS_FMT_YUYV8_2X8; + -+ reg8_write(client, 0x32, 0x01); /* Select TX (CSI) port 0 */ -+ reg8_write(client, 0x33, ((priv->lanes - 1) ^ 0x3) << 4); /* disable CSI output, set CSI lane count, non-continuous CSI mode */ -+ reg8_write(client, 0x20, 0xf0); /* disable port forwarding */ -+#if 0 -+ /* FrameSync setup for REFCLK=25MHz, FPS=30: period_counts=1/2/FPS*25MHz =1/2/30*25Mhz =416666 -> FS_TIME=416666 */ -+ /* FrameSync setup for REFCLK=22.5MHz, FPS=30: period_counts=1/2/FPS*22.5Mhz=1/2/30*22.5Mhz=375000 -> FS_TIME=375000 */ -+// #define FS_TIME (priv->csi_rate == 1450 ? 376000 : 417666) -+ #define FS_TIME (priv->csi_rate == 1450 ? 385000 : 428000) // FPS=29.2 (new vendor's firmware AWB restriction?) -+ reg8_write(client, 0x1a, FS_TIME >> 16); /* FrameSync time 24bit */ -+ reg8_write(client, 0x1b, (FS_TIME >> 8) & 0xff); -+ reg8_write(client, 0x1c, FS_TIME & 0xff); -+ reg8_write(client, 0x18, 0x43); /* Enable FrameSync, 50/50 mode, Frame clock from 25MHz */ -+#else -+ /* FrameSync setup for REFCLK=25MHz, FPS=30: period_counts=1/FPS/12mks=1/30/12e-6=2777 -> HI=2, LO=2775 */ -+ /* FrameSync setup for REFCLK=22.5MHz, FPS=30: period_counts=1/FPS/13.333mks=1/30/13.333e-6=2500 -> HI=2, LO=2498 */ -+ #define FS_TIME (priv->csi_rate == 1450 ? (2498+15) : (2775+15)) -+ reg8_write(client, 0x19, 2 >> 8); /* FrameSync high time MSB */ -+ reg8_write(client, 0x1a, 2 & 0xff); /* FrameSync high time LSB */ -+ reg8_write(client, 0x1b, FS_TIME >> 8); /* FrameSync low time MSB */ -+ reg8_write(client, 0x1c, FS_TIME & 0xff); /* FrameSync low time LSB */ -+ reg8_write(client, 0x18, 0x01); /* Enable FrameSync, HI/LO mode, Frame clock from port0 */ -+#endif ++ return 0; +} + -+//#define SENSOR_ID 0x30 // ov10635 -+//#define SENSOR_ID 0x24 // ov490 -+ -+static void ti954_ti9x3_fpdlink3_setup(struct i2c_client *client, int idx) ++static int ov495_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) +{ -+ struct ti954_ti9x3_priv *priv = i2c_get_clientdata(client); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov495_priv *priv = to_ov495(client); + -+ /* FPDLinkIII setup */ -+ client->addr = priv->des_addr; /* TI954 I2C */ -+ reg8_write(client, 0x4c, (idx << 4) | (1 << idx)); /* Select RX port number */ -+ usleep_range(2000, 2500); /* wait 2ms */ -+ reg8_write(client, 0x58, 0x58); /* Back channel: pass-through/backchannel/CRC enable, Freq=2.5Mbps */ -+ reg8_write(client, 0x5c, priv->ti9x3_addr_map[idx] << 1); /* TI9X3 I2C addr */ -+// reg8_write(client, 0x5d, SENSOR_ID << 1); /* SENSOR I2C native - must be set by sensor driver */ -+// reg8_write(client, 0x65, (0x60 + idx) << 1); /* SENSOR I2C translated - must be set by sensor driver */ -+ if (strcmp(priv->cable_mode, "coax") == 0) { -+ reg8_write(client, 0x6d, 0x7f); /* Coax, RAW10 */ -+ } else if (strcmp(priv->cable_mode, "stp") == 0) { -+ reg8_write(client, 0x6d, 0x78); /* STP, CSI */ -+ } -+ reg8_write(client, 0x70, (idx << 6) | 0x1e); /* CSI data type: yuv422 8-bit, assign VC */ -+ reg8_write(client, 0x7c, 0x81); /* BIT(7) - magic to Use RAW10 as 8-bit mode */ -+ reg8_write(client, 0x6e, 0x88); /* Sensor reset: backchannel GPIO0/GPIO1 set low */ ++ memcpy(edid->edid, priv->id, 6); ++ ++ edid->edid[6] = 0xff; ++ edid->edid[7] = client->addr; ++ edid->edid[8] = OV495_VERSION_REG >> 8; ++ edid->edid[9] = OV495_VERSION_REG & 0xff; ++ ++ return 0; +} + -+static int ti954_ti9x3_initialize(struct i2c_client *client) ++static int ov495_set_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_selection *sel) +{ -+ struct ti954_ti9x3_priv *priv = i2c_get_clientdata(client); -+ int idx; ++ struct v4l2_rect *rect = &sel->r; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov495_priv *priv = to_ov495(client); + -+ dev_info(&client->dev, "LINKs=%d, LANES=%d, FORWARDING=%s, CABLE=%s, ID=%s\n", -+ priv->links, priv->lanes, priv->forwarding_mode, priv->cable_mode, priv->chip_id); ++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE || ++ sel->target != V4L2_SEL_TGT_CROP) ++ return -EINVAL; + -+ ti954_ti9x3_initial_setup(client); ++ rect->left = ALIGN(rect->left, 2); ++ rect->top = ALIGN(rect->top, 2); ++ rect->width = ALIGN(rect->width, 2); ++ rect->height = ALIGN(rect->height, 2); + -+ for (idx = 0; idx < priv->links; idx++) { -+ if (!IS_ERR(priv->poc_supply[idx])) { -+ if (regulator_enable(priv->poc_supply[idx])) -+ dev_err(&client->dev, "fail to enable POC%d regulator\n", idx); -+ mdelay(priv->poc_delay); -+ } ++ if ((rect->left + rect->width > priv->max_width) || ++ (rect->top + rect->height > priv->max_height)) ++ *rect = priv->rect; ++ ++ priv->rect.left = rect->left; ++ priv->rect.top = rect->top; ++ priv->rect.width = rect->width; ++ priv->rect.height = rect->height; ++ ++ return 0; ++} ++ ++static int ov495_get_selection(struct v4l2_subdev *sd, ++ struct v4l2_subdev_pad_config *cfg, ++ struct v4l2_subdev_selection *sel) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov495_priv *priv = to_ov495(client); ++ ++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) ++ return -EINVAL; + -+ ti954_ti9x3_fpdlink3_setup(client, idx); ++ switch (sel->target) { ++ case V4L2_SEL_TGT_CROP_BOUNDS: ++ sel->r.left = 0; ++ sel->r.top = 0; ++ sel->r.width = priv->max_width; ++ sel->r.height = priv->max_height; ++ return 0; ++ case V4L2_SEL_TGT_CROP_DEFAULT: ++ sel->r.left = 0; ++ sel->r.top = 0; ++ sel->r.width = priv->max_width; ++ sel->r.height = priv->max_height; ++ return 0; ++ case V4L2_SEL_TGT_CROP: ++ sel->r = priv->rect; ++ return 0; ++ default: ++ return -EINVAL; + } ++} + -+ client->addr = priv->des_addr; ++static int ov495_g_mbus_config(struct v4l2_subdev *sd, ++ struct v4l2_mbus_config *cfg) ++{ ++ cfg->flags = V4L2_MBUS_CSI2_1_LANE | V4L2_MBUS_CSI2_CHANNEL_0 | ++ V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; ++ cfg->type = V4L2_MBUS_CSI2; + + return 0; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG -+static int ti954_ti9x3_g_register(struct v4l2_subdev *sd, -+ struct v4l2_dbg_register *reg) ++static int ov495_g_register(struct v4l2_subdev *sd, ++ struct v4l2_dbg_register *reg) +{ -+ struct ti954_ti9x3_priv *priv = v4l2_get_subdevdata(sd); -+ struct i2c_client *client = priv->client; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + u8 val = 0; + -+ ret = reg8_read(client, (u8)reg->reg, &val); ++ ret = reg16_read(client, (u16)reg->reg, &val); + if (ret < 0) + return ret; + + reg->val = val; -+ reg->size = sizeof(u8); ++ reg->size = sizeof(u16); + + return 0; +} + -+static int ti954_ti9x3_s_register(struct v4l2_subdev *sd, -+ const struct v4l2_dbg_register *reg) ++static int ov495_s_register(struct v4l2_subdev *sd, ++ const struct v4l2_dbg_register *reg) +{ -+ struct ti954_ti9x3_priv *priv = v4l2_get_subdevdata(sd); -+ struct i2c_client *client = priv->client; ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ int ret; + -+ return reg8_write(client, (u8)reg->reg, (u8)reg->val); ++ ret = reg16_write(client, (u16)reg->reg, (u8)reg->val); ++ if ((u8)reg->reg == 0xFFFD) ++ usleep_range(100, 150); /* wait 100 us */ ++ if ((u8)reg->reg == 0xFFFE) ++ usleep_range(100, 150); /* wait 100 us */ ++ return ret; +} +#endif + -+static int ti954_ti9x3_s_power(struct v4l2_subdev *sd, int on) ++static struct v4l2_subdev_core_ops ov495_core_ops = { ++#ifdef CONFIG_VIDEO_ADV_DEBUG ++ .g_register = ov495_g_register, ++ .s_register = ov495_s_register, ++#endif ++}; ++ ++static int ov495_s_ctrl(struct v4l2_ctrl *ctrl) +{ -+ struct ti954_ti9x3_priv *priv = v4l2_get_subdevdata(sd); -+ struct i2c_client *client = priv->client; ++ struct v4l2_subdev *sd = to_sd(ctrl); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov495_priv *priv = to_ov495(client); ++ int ret = -EINVAL; + -+ if (on) { -+ if (atomic_inc_return(&priv->use_count) == 1) -+ reg8_write(client, 0x20, 0x00); /* enable port forwarding to CSI */ -+ } else { -+ if (atomic_dec_return(&priv->use_count) == 0) -+ reg8_write(client, 0x20, 0xf0); /* disable port forwarding to CSI */ ++ if (!priv->init_complete) ++ return 0; ++ ++ switch (ctrl->id) { ++ case V4L2_CID_BRIGHTNESS: ++ break; ++ case V4L2_CID_CONTRAST: ++ break; ++ case V4L2_CID_SATURATION: ++ break; ++ case V4L2_CID_HUE: ++ break; ++ case V4L2_CID_GAMMA: ++ break; ++ case V4L2_CID_SHARPNESS: ++ break; ++ case V4L2_CID_AUTOGAIN: ++ case V4L2_CID_GAIN: ++ case V4L2_CID_EXPOSURE: ++ break; ++ case V4L2_CID_HFLIP: ++ ret = reg16_write(client, 0x3516, 0x00); ++ ret |= reg16_write(client, 0x0ffc, 0x00); ++ ret |= reg16_write(client, 0x0500, ctrl->val); ++ ret |= reg16_write(client, 0x0501, 0x00); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x30C0, 0xdc); ++ ret |= reg16_write(client, 0x3516, 0x01); ++ break; ++ case V4L2_CID_VFLIP: ++ ret = reg16_write(client, 0x3516, 0x00); ++ ret |= reg16_write(client, 0x0ffc, 0x00); ++ ret |= reg16_write(client, 0x0500, ctrl->val); ++ ret |= reg16_write(client, 0x0501, 0x01); ++ usleep_range(100, 150); /* wait 100 us */ ++ ret |= reg16_write(client, 0x30C0, 0xdc); ++ ret |= reg16_write(client, 0x3516, 0x01); ++ break; ++ case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: ++ ret = 0; ++ break; + } + -+ return 0; ++ return ret; +} + -+static int ti954_ti9x3_registered_async(struct v4l2_subdev *sd) -+{ -+ struct ti954_ti9x3_priv *priv = v4l2_get_subdevdata(sd); -+ struct i2c_client *client = priv->client; -+ -+ reg8_write(client, 0x33, ((priv->lanes - 1) ^ 0x3) << 4 | 0x1); /* enable CSI output, set CSI lane count, non-continuous CSI mode */ ++static const struct v4l2_ctrl_ops ov495_ctrl_ops = { ++ .s_ctrl = ov495_s_ctrl, ++}; + -+ return 0; -+} ++static struct v4l2_subdev_video_ops ov495_video_ops = { ++ .s_stream = ov495_s_stream, ++ .g_mbus_config = ov495_g_mbus_config, ++}; + -+static struct v4l2_subdev_core_ops ti954_ti9x3_subdev_core_ops = { -+#ifdef CONFIG_VIDEO_ADV_DEBUG -+ .g_register = ti954_ti9x3_g_register, -+ .s_register = ti954_ti9x3_s_register, -+#endif -+ .s_power = ti954_ti9x3_s_power, -+ .registered_async = ti954_ti9x3_registered_async, ++static const struct v4l2_subdev_pad_ops ov495_subdev_pad_ops = { ++ .get_edid = ov495_get_edid, ++ .enum_mbus_code = ov495_enum_mbus_code, ++ .get_selection = ov495_get_selection, ++ .set_selection = ov495_set_selection, ++ .get_fmt = ov495_get_fmt, ++ .set_fmt = ov495_set_fmt, +}; + -+static struct v4l2_subdev_ops ti954_ti9x3_subdev_ops = { -+ .core = &ti954_ti9x3_subdev_core_ops, ++static struct v4l2_subdev_ops ov495_subdev_ops = { ++ .core = &ov495_core_ops, ++ .video = &ov495_video_ops, ++ .pad = &ov495_subdev_pad_ops, +}; + -+static int ti954_ti9x3_parse_dt(struct i2c_client *client) ++static void ov495_otp_id_read(struct i2c_client *client) +{ -+ struct ti954_ti9x3_priv *priv = i2c_get_clientdata(client); -+ struct device_node *np = client->dev.of_node; -+ struct device_node *endpoint = NULL, *rendpoint = NULL; -+ struct property *prop; -+ int err, i; -+ int sensor_delay; -+ char forwarding_mode_default[20] = "round-robin"; /* round-robin, synchronized */ -+ char cable_mode_default[5] = "coax"; /* coax, stp */ -+ struct property *csi_rate_prop, *dvp_order_prop; -+ u8 val = 0; ++ struct ov495_priv *priv = to_ov495(client); ++ int i; + -+ if (of_property_read_u32(np, "ti,links", &priv->links)) -+ priv->links = 2; ++#if 0 ++ /* read camera id from ov495 OTP memory */ ++ reg16_write(client, 0xFFFD, 0x80); ++ reg16_write(client, 0xFFFE, 0x20); ++ usleep_range(100, 150); /* wait 100 us */ ++ reg16_write(client, 0x7384, 0x40); /* manual mode, bank#0 */ ++ reg16_write(client, 0x7381, 1); /* start OTP read */ + -+ if (of_property_read_u32(np, "ti,lanes", &priv->lanes)) -+ priv->lanes = 4; ++ usleep_range(25000, 26000); /* wait 25 ms */ + -+ priv->xtal_gpio = of_get_gpio(np, 0); -+ if (priv->xtal_gpio > 0) { -+ err = devm_gpio_request_one(&client->dev, priv->xtal_gpio, GPIOF_OUT_INIT_LOW, dev_name(&client->dev)); -+ if (err) -+ dev_err(&client->dev, "cannot request XTAL gpio %d: %d\n", priv->xtal_gpio, err); -+ else -+ mdelay(250); ++ for (i = 0; i < 6; i++) ++ reg16_read(client, 0x7300 + i + 4, &priv->id[i]); ++#else ++ /* read camera id from ov2775 OTP memory */ ++ reg16_write(client, 0x3516, 0x00); /* unlock write */ ++ reg16_write(client, 0x0FFC, 0); ++ reg16_write(client, 0x0500, 0x00); /* write 0x34a1 -> 1 */ ++ reg16_write(client, 0x0501, 0x34); ++ reg16_write(client, 0x0502, 0xa1); ++ reg16_write(client, 0x0503, 1); ++ reg16_write(client, 0x30C0, 0xc1); ++ ++ usleep_range(25000, 25500); /* wait 25 ms */ ++ ++ for (i = 0; i < 6; i++) { ++ reg16_write(client, 0x3516, 0x00); /* unlock write */ ++ reg16_write(client, 0x0500, 0x01); /* read (0x7a00 + i) */ ++ reg16_write(client, 0x0501, 0x7a); ++ reg16_write(client, 0x0502, 0x00 + i + (i < 3 ? 11 : 3)); /* take bytes 11,12,13,6,7,8 */ ++ reg16_write(client, 0x30C0, 0xc1); ++ usleep_range(1000, 1500); /* wait 1 ms */ ++ reg16_read(client, 0x0500, &priv->id[i]); + } ++#endif ++} + -+ reg8_read(client, 0x00, &val); /* read TI954 I2C address */ -+ if (val != (priv->des_addr << 1)) { -+ prop = of_find_property(np, "reg", NULL); -+ if (prop) -+ of_remove_property(np, prop); -+ return -ENODEV; ++static ssize_t ov495_otp_id_show(struct device *dev, ++ struct device_attribute *attr, char *buf) ++{ ++ struct v4l2_subdev *sd = i2c_get_clientdata(to_i2c_client(dev)); ++ struct i2c_client *client = v4l2_get_subdevdata(sd); ++ struct ov495_priv *priv = to_ov495(client); ++ ++ return snprintf(buf, 32, "%02x:%02x:%02x:%02x:%02x:%02x\n", ++ priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); ++} ++ ++static DEVICE_ATTR(otp_id_ov495, S_IRUGO, ov495_otp_id_show, NULL); ++ ++static int ov495_initialize(struct i2c_client *client) ++{ ++ struct ov495_priv *priv = to_ov495(client); ++ u8 pid = 0, ver = 0; ++ int ret = 0; ++ ++ /* check and show product ID and manufacturer ID */ ++ reg16_write(client, 0xFFFD, 0x80); ++ reg16_write(client, 0xFFFE, 0x80); ++ usleep_range(100, 150); /* wait 100 us */ ++ reg16_read(client, OV495_PID, &pid); ++ reg16_read(client, OV495_VER, &ver); ++ ++ if (OV495_VERSION(pid, ver) != OV495_VERSION_REG) { ++ dev_err(&client->dev, "Product ID error %x:%x\n", pid, ver); ++ ret = -ENODEV; ++ goto err; + } + -+ ti954_ti9x3_read_chipid(client); ++ if (unlikely(force_conf_link)) ++ goto out; + -+ indirect_write(client, 7, 0x15, 0x30); -+ gpio_set_value(priv->xtal_gpio, 1); -+ usleep_range(5000, 5500); /* wait 5ms */ -+ indirect_write(client, 7, 0x15, 0); ++#if 0 ++ /* read resolution used by current firmware */ ++ reg16_write(client, 0xFFFD, 0x80); ++ reg16_write(client, 0xFFFE, 0x82); ++ usleep_range(100, 150); /* wait 100 us */ ++ reg16_read(client, OV495_ISP_HSIZE_HIGH, &val); ++ priv->max_width = val; ++ reg16_read(client, OV495_ISP_HSIZE_LOW, &val); ++ priv->max_width = (priv->max_width << 8) | val; ++ reg16_read(client, OV495_ISP_VSIZE_HIGH, &val); ++ priv->max_height = val; ++ reg16_read(client, OV495_ISP_VSIZE_LOW, &val); ++ priv->max_height = (priv->max_height << 8) | val; ++#else ++ priv->max_width = 1920; ++ priv->max_height = 1080; ++#endif + -+ if (!of_property_read_u32(np, "ti,sensor_delay", &sensor_delay)) -+ mdelay(sensor_delay); -+ if (of_property_read_string(np, "ti,forwarding-mode", &priv->forwarding_mode)) -+ priv->forwarding_mode = forwarding_mode_default; -+ if (of_property_read_string(np, "ti,cable-mode", &priv->cable_mode)) -+ priv->cable_mode = cable_mode_default; -+ if (of_property_read_u32(np, "ti,poc-delay", &priv->poc_delay)) -+ priv->poc_delay = 50; ++ /* set virtual channel */ ++ ov495_regs_wizard[3].val = 0x1e | (priv->port << 6); ++ /* Program wizard registers */ ++ ov495_set_regs(client, ov495_regs_wizard, ARRAY_SIZE(ov495_regs_wizard)); ++ /* Read OTP IDs */ ++ ov495_otp_id_read(client); + -+ /* module params override dts */ -+ if (poc_delay) -+ priv->poc_delay = poc_delay; ++out: ++ dev_info(&client->dev, "ov495/ov2775 PID %x%x, res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n", ++ pid, ver, priv->max_width, priv->max_height, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]); ++err: ++ return ret; ++} ++ ++static int ov495_parse_dt(struct device_node *np, struct ov495_priv *priv) ++{ ++ struct i2c_client *client = v4l2_get_subdevdata(&priv->sd); ++ int i; ++ struct device_node *endpoint = NULL, *rendpoint = NULL; ++ int tmp_addr = 0; + + for (i = 0; ; i++) { + endpoint = of_graph_get_next_endpoint(np, endpoint); @@ -6908,130 +6905,186 @@ index 0000000..ff84128 + + of_node_put(endpoint); + -+ if (i < priv->links) { -+ if (of_property_read_u32(endpoint, "ti9x3-addr", &priv->ti9x3_addr_map[i])) { -+ dev_err(&client->dev, "ti9x3-addr not set\n"); -+ return -EINVAL; -+ } -+ priv->sd_of_node[i] = endpoint; -+ } ++ rendpoint = of_parse_phandle(endpoint, "remote-endpoint", 0); ++ if (!rendpoint) ++ continue; ++ ++ if (!of_property_read_u32(rendpoint, "ti9x3-addr", &priv->ti9x3_addr) && ++ !of_property_match_string(rendpoint->parent->parent, "compatible", "ti,ti9x4") && ++ !of_property_read_u32(rendpoint->parent->parent, "reg", &priv->ti9x4_addr) && ++ !kstrtouint(strrchr(rendpoint->full_name, '@') + 1, 0, &priv->port)) ++ break; ++ } ++ ++ if (!priv->ti9x4_addr) { ++ dev_err(&client->dev, "deserializer does not present for OV495\n"); ++ return -EINVAL; ++ } + -+ rendpoint = of_parse_phandle(endpoint, "remote-endpoint", 0); -+ if (!rendpoint) -+ continue; ++ /* setup I2C translator address */ ++ tmp_addr = client->addr; ++ if (priv->ti9x4_addr) { ++ client->addr = priv->ti9x4_addr; /* Deserializer I2C address */ + -+ csi_rate_prop = of_find_property(endpoint, "csi-rate", NULL); -+ if (csi_rate_prop) { -+ of_property_read_u32(endpoint, "csi-rate", &priv->csi_rate); -+ of_update_property(rendpoint, csi_rate_prop); -+ } ++ reg8_write(client, 0x4c, (priv->port << 4) | (1 << priv->port)); /* Select RX port number */ ++ usleep_range(2000, 2500); /* wait 2ms */ ++ reg8_write(client, 0x65, tmp_addr << 1); /* Sensor translated I2C address */ ++ reg8_write(client, 0x5d, OV495_I2C_ADDR << 1); /* Sensor native I2C address */ + -+ dvp_order_prop = of_find_property(endpoint, "dvp-order", NULL); -+ if (dvp_order_prop) -+ of_update_property(rendpoint, dvp_order_prop); ++ reg8_write(client, 0x6e, 0x9a); /* GPIO0 - fsin, GPIO1 - resetb */ ++ /* TODO: why too long? move logic to workqueue? */ ++ mdelay(350); /* time needed to boot all sensor IPs */ + } ++ client->addr = tmp_addr; + + return 0; +} + -+static int ti954_ti9x3_probe(struct i2c_client *client, -+ const struct i2c_device_id *did) ++static int ov495_probe(struct i2c_client *client, ++ const struct i2c_device_id *did) +{ -+ struct ti954_ti9x3_priv *priv; -+ int err, i; -+ char supply_name[10]; ++ struct ov495_priv *priv; ++ struct v4l2_ctrl *ctrl; ++ int ret; + + priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + -+ i2c_set_clientdata(client, priv); -+ priv->des_addr = client->addr; -+ priv->client = client; -+ atomic_set(&priv->use_count, 0); ++ v4l2_i2c_subdev_init(&priv->sd, client, &ov495_subdev_ops); ++ priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; + -+ err = ti954_ti9x3_parse_dt(client); -+ if (err) -+ goto out; ++ priv->exposure = 0x100; ++ priv->gain = 0x100; ++ priv->autogain = 1; ++ v4l2_ctrl_handler_init(&priv->hdl, 4); ++ v4l2_ctrl_new_std(&priv->hdl, &ov495_ctrl_ops, ++ V4L2_CID_BRIGHTNESS, 0, 16, 1, 7); ++ v4l2_ctrl_new_std(&priv->hdl, &ov495_ctrl_ops, ++ V4L2_CID_CONTRAST, 0, 16, 1, 7); ++ v4l2_ctrl_new_std(&priv->hdl, &ov495_ctrl_ops, ++ V4L2_CID_SATURATION, 0, 7, 1, 2); ++ v4l2_ctrl_new_std(&priv->hdl, &ov495_ctrl_ops, ++ V4L2_CID_HUE, 0, 23, 1, 12); ++ v4l2_ctrl_new_std(&priv->hdl, &ov495_ctrl_ops, ++ V4L2_CID_GAMMA, -128, 128, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &ov495_ctrl_ops, ++ V4L2_CID_SHARPNESS, 0, 10, 1, 3); ++ v4l2_ctrl_new_std(&priv->hdl, &ov495_ctrl_ops, ++ V4L2_CID_AUTOGAIN, 0, 1, 1, priv->autogain); ++ v4l2_ctrl_new_std(&priv->hdl, &ov495_ctrl_ops, ++ V4L2_CID_GAIN, 0, 0xffff, 1, priv->gain); ++ v4l2_ctrl_new_std(&priv->hdl, &ov495_ctrl_ops, ++ V4L2_CID_EXPOSURE, 0, 0xffff, 1, priv->exposure); ++ v4l2_ctrl_new_std(&priv->hdl, &ov495_ctrl_ops, ++ V4L2_CID_HFLIP, 0, 1, 1, 0); ++ v4l2_ctrl_new_std(&priv->hdl, &ov495_ctrl_ops, ++ V4L2_CID_VFLIP, 0, 1, 1, 0); ++ ctrl = v4l2_ctrl_new_std(&priv->hdl, &ov495_ctrl_ops, ++ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 9); ++ if (ctrl) ++ ctrl->flags &= ~V4L2_CTRL_FLAG_READ_ONLY; ++ priv->sd.ctrl_handler = &priv->hdl; + -+ for (i = 0; i < 4; i++) { -+ sprintf(supply_name, "POC%d", i); -+ priv->poc_supply[i] = devm_regulator_get_optional(&client->dev, supply_name); -+ } ++ ret = priv->hdl.error; ++ if (ret) ++ goto cleanup; + -+ err = ti954_ti9x3_initialize(client); -+ if (err < 0) -+ goto out; ++ v4l2_ctrl_handler_setup(&priv->hdl); + -+ for (i = 0; i < priv->links; i++) { -+ v4l2_subdev_init(&priv->sd[i], &ti954_ti9x3_subdev_ops); -+ priv->sd[i].owner = client->dev.driver->owner; -+ priv->sd[i].dev = &client->dev; -+ priv->sd[i].grp_id = i; -+ v4l2_set_subdevdata(&priv->sd[i], priv); -+ priv->sd[i].of_node = priv->sd_of_node[i]; ++ priv->pad.flags = MEDIA_PAD_FL_SOURCE; ++ priv->sd.entity.flags |= MEDIA_ENT_F_CAM_SENSOR; ++ ret = media_entity_pads_init(&priv->sd.entity, 1, &priv->pad); ++ if (ret < 0) ++ goto cleanup; + -+ snprintf(priv->sd[i].name, V4L2_SUBDEV_NAME_SIZE, "%s %d-%04x", -+ client->dev.driver->name, i2c_adapter_id(client->adapter), -+ client->addr); ++ ret = ov495_parse_dt(client->dev.of_node, priv); ++ if (ret) ++ goto cleanup; + -+ err = v4l2_async_register_subdev(&priv->sd[i]); -+ if (err < 0) -+ goto out; ++ ret = ov495_initialize(client); ++ if (ret < 0) ++ goto cleanup; ++ ++ priv->rect.left = 0; ++ priv->rect.top = 0; ++ priv->rect.width = priv->max_width; ++ priv->rect.height = priv->max_height; ++ ++ ret = v4l2_async_register_subdev(&priv->sd); ++ if (ret) ++ goto cleanup; ++ ++ if (device_create_file(&client->dev, &dev_attr_otp_id_ov495) != 0) { ++ dev_err(&client->dev, "sysfs otp_id entry creation failed\n"); ++ goto cleanup; + } + -+out: -+ return err; ++ priv->init_complete = 1; ++ ++ return 0; ++ ++cleanup: ++ media_entity_cleanup(&priv->sd.entity); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ v4l2_device_unregister_subdev(&priv->sd); ++#ifdef CONFIG_SOC_CAMERA_OV495_OV2775 ++ v4l_err(client, "failed to probe @ 0x%02x (%s)\n", ++ client->addr, client->adapter->name); ++#endif ++ return ret; +} + -+static int ti954_ti9x3_remove(struct i2c_client *client) ++static int ov495_remove(struct i2c_client *client) +{ -+ struct ti954_ti9x3_priv *priv = i2c_get_clientdata(client); -+ int i; ++ struct ov495_priv *priv = i2c_get_clientdata(client); + -+ for (i = 0; i < priv->links; i++) { -+ v4l2_async_unregister_subdev(&priv->sd[i]); -+ v4l2_device_unregister_subdev(&priv->sd[i]); -+ } ++ device_remove_file(&client->dev, &dev_attr_otp_id_ov495); ++ v4l2_async_unregister_subdev(&priv->sd); ++ media_entity_cleanup(&priv->sd.entity); ++ v4l2_ctrl_handler_free(&priv->hdl); ++ v4l2_device_unregister_subdev(&priv->sd); + + return 0; +} + -+static const struct of_device_id ti954_ti9x3_dt_ids[] = { -+ { .compatible = "ti,ti954-ti9x3" }, -+ {}, ++#ifdef CONFIG_SOC_CAMERA_OV495_OV2775 ++static const struct i2c_device_id ov495_id[] = { ++ { "ov495-ov2775", 0 }, ++ { } +}; -+MODULE_DEVICE_TABLE(of, ti954_ti9x3_dt_ids); ++MODULE_DEVICE_TABLE(i2c, ov495_id); + -+static const struct i2c_device_id ti954_ti9x3_id[] = { -+ { "ti954_ti9x3", 0 }, ++static const struct of_device_id ov495_of_ids[] = { ++ { .compatible = "ovti,ov495-ov2775", }, + { } +}; -+MODULE_DEVICE_TABLE(i2c, ti954_ti9x3_id); ++MODULE_DEVICE_TABLE(of, ov495_of_ids); + -+static struct i2c_driver ti954_ti9x3_i2c_driver = { ++static struct i2c_driver ov495_i2c_driver = { + .driver = { -+ .name = "ti954_ti9x3", -+ .of_match_table = of_match_ptr(ti954_ti9x3_dt_ids), ++ .name = "ov495-ov2775", ++ .of_match_table = ov495_of_ids, + }, -+ .probe = ti954_ti9x3_probe, -+ .remove = ti954_ti9x3_remove, -+ .id_table = ti954_ti9x3_id, ++ .probe = ov495_probe, ++ .remove = ov495_remove, ++ .id_table = ov495_id, +}; + -+module_i2c_driver(ti954_ti9x3_i2c_driver); ++module_i2c_driver(ov495_i2c_driver); + -+MODULE_DESCRIPTION("FPDLinkIII driver for TI954-TI9X3"); ++MODULE_DESCRIPTION("SoC Camera driver for OV495-OV2775"); +MODULE_AUTHOR("Vladimir Barinov"); +MODULE_LICENSE("GPL"); -diff --git a/drivers/media/i2c/soc_camera/ti964_ti9x3.c b/drivers/media/i2c/soc_camera/ti964_ti9x3.c ++#endif +diff --git a/drivers/media/i2c/soc_camera/ov495_ov2775.h b/drivers/media/i2c/soc_camera/ov495_ov2775.h new file mode 100644 -index 0000000..8393392 +index 0000000..3f53689 --- /dev/null -+++ b/drivers/media/i2c/soc_camera/ti964_ti9x3.c -@@ -0,0 +1,408 @@ ++++ b/drivers/media/i2c/soc_camera/ov495_ov2775.h +@@ -0,0 +1,23 @@ +/* -+ * TI (ti964/ti960)-(ti913/ti953) FPDLinkIII driver ++ * OmniVision ov495-ov2775 sensor camera wizard 1280x1080@30/UYVY/BT601/8bit + * + * Copyright (C) 2017 Cogent Embedded, Inc. + * @@ -7041,6 +7094,35 @@ index 0000000..8393392 + * option) any later version. + */ + ++struct ov495_reg { ++ u16 reg; ++ u8 val; ++}; ++ ++static struct ov495_reg ov495_regs_wizard[] = { ++{0x3516, 0x00}, /* unlock write */ ++{0xFFFD, 0x80}, ++{0xFFFE, 0x20}, ++{0x8017, 0x1e | (0 << 6)}, ++{0x7c10, 0x01}, /* UYVY */ ++}; +diff --git a/drivers/media/i2c/soc_camera/ti9x4.c b/drivers/media/i2c/soc_camera/ti9x4.c +new file mode 100644 +index 0000000..aac892b +--- /dev/null ++++ b/drivers/media/i2c/soc_camera/ti9x4.c +@@ -0,0 +1,520 @@ ++/* ++ * TI DS90UB954/960/964 FPDLinkIII driver ++ * ++ * Copyright (C) 2017-2018 Cogent Embedded, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ +#include +#include +#include @@ -7054,9 +7136,9 @@ index 0000000..8393392 +#include +#include + -+#include "ti9x4_ti9x3.h" ++#include "ti9x4.h" + -+struct ti964_ti9x3_priv { ++struct ti9x4_priv { + struct v4l2_subdev sd[4]; + struct device_node *sd_of_node[4]; + int des_addr; @@ -7064,22 +7146,72 @@ index 0000000..8393392 + int lanes; + int csi_rate; + const char *forwarding_mode; -+ const char *cable_mode; ++ int is_coax; ++ int dvp_bus; ++ int hsync; ++ int vsync; + int poc_delay; + atomic_t use_count; + struct i2c_client *client; + int ti9x3_addr_map[4]; + char chip_id[6]; ++ int ser_id; + struct regulator *poc_supply[4]; /* PoC power supply */ +}; + ++static int ser_id; ++module_param(ser_id, int, 0644); ++MODULE_PARM_DESC(ser_id, " Serializer ID (default: TI913)"); ++ ++static int is_stp; ++module_param(is_stp, int, 0644); ++MODULE_PARM_DESC(is_stp, " STP cable (default: Coax cable)"); ++ ++static int dvp_bus = 8; ++module_param(dvp_bus, int, 0644); ++MODULE_PARM_DESC(dvp_bus, " DVP/CSI over FPDLink (default: DVP 8-bit)"); ++ ++static int hsync; ++module_param(hsync, int, 0644); ++MODULE_PARM_DESC(hsync, " HSYNC invertion (default: 0 - not inverted)"); ++ ++static int vsync = 1; ++module_param(vsync, int, 0644); ++MODULE_PARM_DESC(vsync, " VSYNC invertion (default: 1 - inverted)"); ++ +static int poc_delay; +module_param(poc_delay, int, 0644); -+MODULE_PARM_DESC(poc_delay, " Delay in ms after POC enable (default: 0 ms) */"); ++MODULE_PARM_DESC(poc_delay, " Delay in ms after POC enable (default: 0 ms)"); ++ ++#ifdef TI954_SILICON_ERRATA ++static int indirect_write(struct i2c_client *client, unsigned int page, u8 reg, u8 val) ++{ ++ if (page > 7) ++ return -EINVAL; ++ ++ reg8_write(client, 0xb0, page << 2); ++ reg8_write(client, 0xb1, reg); ++ reg8_write(client, 0xb2, val); ++ ++ return 0; ++} ++ ++static int indirect_read(struct i2c_client *client, unsigned int page, u8 reg, u8 *val) ++{ ++ if (page > 7) ++ return -EINVAL; ++ ++ reg8_write(client, 0xb0, page << 2); ++ reg8_write(client, 0xb1, reg); ++ reg8_read(client, 0xb2, val); ++ ++ return 0; ++} ++#endif + -+static void ti964_ti9x3_read_chipid(struct i2c_client *client) ++static void ti9x4_read_chipid(struct i2c_client *client) +{ -+ struct ti964_ti9x3_priv *priv = i2c_get_clientdata(client); ++ struct ti9x4_priv *priv = i2c_get_clientdata(client); + + /* Chip ID */ + reg8_read(client, 0xf1, &priv->chip_id[0]); @@ -7090,12 +7222,12 @@ index 0000000..8393392 + priv->chip_id[5] = '\0'; +} + -+static void ti964_ti9x3_initial_setup(struct i2c_client *client) ++static void ti9x4_initial_setup(struct i2c_client *client) +{ -+ struct ti964_ti9x3_priv *priv = i2c_get_clientdata(client); ++ struct ti9x4_priv *priv = i2c_get_clientdata(client); + + /* Initial setup */ -+ client->addr = priv->des_addr; /* TI964 I2C */ ++ client->addr = priv->des_addr; /* TI9x4 I2C */ + reg8_write(client, 0x08, 0x1c); /* I2C glitch filter depth */ + reg8_write(client, 0x0a, 0x79); /* I2C high pulse width */ + reg8_write(client, 0x0b, 0x79); /* I2C low pulse width */ @@ -7141,7 +7273,7 @@ index 0000000..8393392 + reg8_write(client, 0x19, 2 >> 8); /* FrameSync high time MSB */ + reg8_write(client, 0x1a, 2 & 0xff); /* FrameSync high time LSB */ + reg8_write(client, 0x1b, FS_TIME >> 8); /* FrameSync low time MSB */ -+ reg8_write(client, 0x1c, FS_TIME & 0xff); /* FrameSync low time LSB */ ++ reg8_write(client, 0x1c, FS_TIME & 0xff); /* FrameSync low time LSB */ + reg8_write(client, 0x18, 0x01); /* Enable FrameSync, HI/LO mode, Frame clock from port0 */ +#endif +} @@ -7149,37 +7281,73 @@ index 0000000..8393392 +//#define SENSOR_ID 0x30 // ov10635 +//#define SENSOR_ID 0x24 // ov490 + -+static void ti964_ti9x3_fpdlink3_setup(struct i2c_client *client, int idx) ++static void ti9x4_fpdlink3_setup(struct i2c_client *client, int idx) +{ -+ struct ti964_ti9x3_priv *priv = i2c_get_clientdata(client); ++ struct ti9x4_priv *priv = i2c_get_clientdata(client); ++ u8 port_config = 0x78; ++ u8 port_config2 = 0; + + /* FPDLinkIII setup */ -+ client->addr = priv->des_addr; /* TI964 I2C */ ++ client->addr = priv->des_addr; /* TI9x4 I2C */ + reg8_write(client, 0x4c, (idx << 4) | (1 << idx)); /* Select RX port number */ + usleep_range(2000, 2500); /* wait 2ms */ -+ reg8_write(client, 0x58, 0x58); /* Back channel: pass-through/backchannel/CRC enable, Freq=2.5Mbps */ ++ ++ switch (priv->ser_id) { ++ case TI913_ID: ++ reg8_write(client, 0x58, 0x58); /* Back channel: Freq=2.5Mbps */ ++ break; ++ case TI953_ID: ++ reg8_write(client, 0x58, 0x5e); /* Back channel: Freq=50Mbps */ ++ break; ++ default: ++ break; ++ } ++ + reg8_write(client, 0x5c, priv->ti9x3_addr_map[idx] << 1); /* TI9X3 I2C addr */ +// reg8_write(client, 0x5d, SENSOR_ID << 1); /* SENSOR I2C native - must be set by sensor driver */ +// reg8_write(client, 0x65, (0x60 + idx) << 1); /* SENSOR I2C translated - must be set by sensor driver */ -+ if (strcmp(priv->cable_mode, "coax") == 0) { -+ reg8_write(client, 0x6d, 0x7f); /* Coax, RAW10 */ -+ } else if (strcmp(priv->cable_mode, "stp") == 0) { -+ reg8_write(client, 0x6d, 0x78); /* STP, CSI */ ++ ++ if (priv->is_coax) ++ port_config |= 0x04; /* Coax */ ++ else ++ port_config |= 0x00; /* STP */ ++ ++ switch (priv->dvp_bus) { ++ case 8: ++ port_config2 |= 0x80; /* RAW10 as 8-bit prosessing using upper bits */ ++ /* fall through */ ++ case 10: ++ port_config |= 0x03; /* DVP over FPDLink (TI913 compatible) RAW10/RAW8 */ ++ break; ++ case 12: ++ port_config |= 0x02; /* DVP over FPDLink (TI913 compatible) RAW12 */ ++ break; ++ default: ++ port_config |= 0x00; /* CSI over FPDLink (TI953 compatible) */ + } ++ ++ if (priv->vsync) ++ port_config2 |= 0x01; /* VSYNC acive low */ ++ if (priv->hsync) ++ port_config2 |= 0x02; /* HSYNC acive low */ ++ ++ reg8_write(client, 0x6d, port_config); ++ reg8_write(client, 0x7c, port_config2); + reg8_write(client, 0x70, (idx << 6) | 0x1e); /* CSI data type: yuv422 8-bit, assign VC */ -+ reg8_write(client, 0x7c, 0x81); /* BIT(7) - magic to Use RAW10 as 8-bit mode */ ++ reg8_write(client, 0x71, (idx << 6) | 0x2a); /* CSI data type: RAW8, assign VC */ ++ reg8_write(client, 0xbc, 0x00); /* Setup minimal time between FV and LV to 3 PCLKs */ + reg8_write(client, 0x6e, 0x88); /* Sensor reset: backchannel GPIO0/GPIO1 set low */ +} + -+static int ti964_ti9x3_initialize(struct i2c_client *client) ++static int ti9x4_initialize(struct i2c_client *client) +{ -+ struct ti964_ti9x3_priv *priv = i2c_get_clientdata(client); ++ struct ti9x4_priv *priv = i2c_get_clientdata(client); + int idx; + + dev_info(&client->dev, "LINKs=%d, LANES=%d, FORWARDING=%s, CABLE=%s, ID=%s\n", -+ priv->links, priv->lanes, priv->forwarding_mode, priv->cable_mode, priv->chip_id); ++ priv->links, priv->lanes, priv->forwarding_mode, priv->is_coax ? "coax" : "stp", priv->chip_id); + -+ ti964_ti9x3_initial_setup(client); ++ ti9x4_initial_setup(client); + + for (idx = 0; idx < priv->links; idx++) { + if (!IS_ERR(priv->poc_supply[idx])) { @@ -7188,7 +7356,7 @@ index 0000000..8393392 + mdelay(priv->poc_delay); + } + -+ ti964_ti9x3_fpdlink3_setup(client, idx); ++ ti9x4_fpdlink3_setup(client, idx); + } + + client->addr = priv->des_addr; @@ -7197,10 +7365,10 @@ index 0000000..8393392 +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG -+static int ti964_ti9x3_g_register(struct v4l2_subdev *sd, ++static int ti9x4_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ -+ struct ti964_ti9x3_priv *priv = v4l2_get_subdevdata(sd); ++ struct ti9x4_priv *priv = v4l2_get_subdevdata(sd); + struct i2c_client *client = priv->client; + int ret; + u8 val = 0; @@ -7215,19 +7383,19 @@ index 0000000..8393392 + return 0; +} + -+static int ti964_ti9x3_s_register(struct v4l2_subdev *sd, ++static int ti9x4_s_register(struct v4l2_subdev *sd, + const struct v4l2_dbg_register *reg) +{ -+ struct ti964_ti9x3_priv *priv = v4l2_get_subdevdata(sd); ++ struct ti9x4_priv *priv = v4l2_get_subdevdata(sd); + struct i2c_client *client = priv->client; + + return reg8_write(client, (u8)reg->reg, (u8)reg->val); +} +#endif + -+static int ti964_ti9x3_s_power(struct v4l2_subdev *sd, int on) ++static int ti9x4_s_power(struct v4l2_subdev *sd, int on) +{ -+ struct ti964_ti9x3_priv *priv = v4l2_get_subdevdata(sd); ++ struct ti9x4_priv *priv = v4l2_get_subdevdata(sd); + struct i2c_client *client = priv->client; + + if (on) { @@ -7241,9 +7409,9 @@ index 0000000..8393392 + return 0; +} + -+static int ti964_ti9x3_registered_async(struct v4l2_subdev *sd) ++static int ti9x4_registered_async(struct v4l2_subdev *sd) +{ -+ struct ti964_ti9x3_priv *priv = v4l2_get_subdevdata(sd); ++ struct ti9x4_priv *priv = v4l2_get_subdevdata(sd); + struct i2c_client *client = priv->client; + + reg8_write(client, 0x33, ((priv->lanes - 1) ^ 0x3) << 4 | 0x1); /* enable CSI output, set CSI lane count, non-continuous CSI mode */ @@ -7251,29 +7419,28 @@ index 0000000..8393392 + return 0; +} + -+static struct v4l2_subdev_core_ops ti964_ti9x3_subdev_core_ops = { ++static struct v4l2_subdev_core_ops ti9x4_subdev_core_ops = { +#ifdef CONFIG_VIDEO_ADV_DEBUG -+ .g_register = ti964_ti9x3_g_register, -+ .s_register = ti964_ti9x3_s_register, ++ .g_register = ti9x4_g_register, ++ .s_register = ti9x4_s_register, +#endif -+ .s_power = ti964_ti9x3_s_power, -+ .registered_async = ti964_ti9x3_registered_async, ++ .s_power = ti9x4_s_power, ++ .registered_async = ti9x4_registered_async, +}; + -+static struct v4l2_subdev_ops ti964_ti9x3_subdev_ops = { -+ .core = &ti964_ti9x3_subdev_core_ops, ++static struct v4l2_subdev_ops ti9x4_subdev_ops = { ++ .core = &ti9x4_subdev_core_ops, +}; + -+static int ti964_ti9x3_parse_dt(struct i2c_client *client) ++static int ti9x4_parse_dt(struct i2c_client *client) +{ -+ struct ti964_ti9x3_priv *priv = i2c_get_clientdata(client); ++ struct ti9x4_priv *priv = i2c_get_clientdata(client); + struct device_node *np = client->dev.of_node; + struct device_node *endpoint = NULL, *rendpoint = NULL; + struct property *prop; + int err, pwen, i; + int sensor_delay; + char forwarding_mode_default[20] = "round-robin"; /* round-robin, synchronized */ -+ char cable_mode_default[5] = "coax"; /* coax, stp */ + struct property *csi_rate_prop, *dvp_order_prop; + u8 val = 0; + @@ -7285,14 +7452,14 @@ index 0000000..8393392 + + pwen = of_get_gpio(np, 0); + if (pwen > 0) { -+ err = devm_gpio_request_one(&client->dev, pwen, GPIOF_OUT_INIT_HIGH, dev_name(&client->dev)); ++ err = devm_gpio_request_one(&client->dev, pwen, GPIOF_OUT_INIT_LOW, dev_name(&client->dev)); + if (err) + dev_err(&client->dev, "cannot request PWEN gpio %d: %d\n", pwen, err); + else + mdelay(250); + } + -+ reg8_read(client, 0x00, &val); /* read TI964 I2C address */ ++ reg8_read(client, 0x00, &val); /* read TI9x4 I2C address */ + if (val != (priv->des_addr << 1)) { + prop = of_find_property(np, "reg", NULL); + if (prop) @@ -7300,18 +7467,45 @@ index 0000000..8393392 + return -ENODEV; + } + -+ ti964_ti9x3_read_chipid(client); ++ ti9x4_read_chipid(client); + ++#ifdef TI954_SILICON_ERRATA ++ indirect_write(client, 7, 0x15, 0x30); ++ if (pwen > 0) ++ gpio_set_value(pwen, 1); ++ usleep_range(5000, 5500); /* wait 5ms */ ++ indirect_write(client, 7, 0x15, 0); ++#endif + if (!of_property_read_u32(np, "ti,sensor_delay", &sensor_delay)) + mdelay(sensor_delay); + if (of_property_read_string(np, "ti,forwarding-mode", &priv->forwarding_mode)) + priv->forwarding_mode = forwarding_mode_default; -+ if (of_property_read_string(np, "ti,cable-mode", &priv->cable_mode)) -+ priv->cable_mode = cable_mode_default; ++ if (of_property_read_bool(np, "ti,stp")) ++ priv->is_coax = 0; ++ else ++ priv->is_coax = 1; ++ if (of_property_read_u32(np, "ti,dvp_bus", &priv->dvp_bus)) ++ priv->dvp_bus = 8; ++ if (of_property_read_u32(np, "ti,hsync", &priv->hsync)) ++ priv->vsync = 0; ++ if (of_property_read_u32(np, "ti,vsync", &priv->vsync)) ++ priv->vsync = 1; ++ if (of_property_read_u32(np, "ti,ser_id", &priv->ser_id)) ++ priv->ser_id = TI913_ID; + if (of_property_read_u32(np, "ti,poc-delay", &priv->poc_delay)) + priv->poc_delay = 50; + + /* module params override dts */ ++ if (is_stp) ++ priv->is_coax = 0; ++ if (dvp_bus != 8) ++ priv->dvp_bus = dvp_bus; ++ if (hsync) ++ priv->hsync = hsync; ++ if (!vsync) ++ priv->vsync = vsync; ++ if (ser_id) ++ priv->ser_id = ser_id; + if (poc_delay) + priv->poc_delay = poc_delay; + @@ -7348,10 +7542,10 @@ index 0000000..8393392 + return 0; +} + -+static int ti964_ti9x3_probe(struct i2c_client *client, ++static int ti9x4_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ -+ struct ti964_ti9x3_priv *priv; ++ struct ti9x4_priv *priv; + int err, i; + char supply_name[10]; + @@ -7364,7 +7558,7 @@ index 0000000..8393392 + priv->client = client; + atomic_set(&priv->use_count, 0); + -+ err = ti964_ti9x3_parse_dt(client); ++ err = ti9x4_parse_dt(client); + if (err) + goto out; + @@ -7373,12 +7567,12 @@ index 0000000..8393392 + priv->poc_supply[i] = devm_regulator_get_optional(&client->dev, supply_name); + } + -+ err = ti964_ti9x3_initialize(client); ++ err = ti9x4_initialize(client); + if (err < 0) + goto out; + + for (i = 0; i < priv->links; i++) { -+ v4l2_subdev_init(&priv->sd[i], &ti964_ti9x3_subdev_ops); ++ v4l2_subdev_init(&priv->sd[i], &ti9x4_subdev_ops); + priv->sd[i].owner = client->dev.driver->owner; + priv->sd[i].dev = &client->dev; + priv->sd[i].grp_id = i; @@ -7398,9 +7592,9 @@ index 0000000..8393392 + return err; +} + -+static int ti964_ti9x3_remove(struct i2c_client *client) ++static int ti9x4_remove(struct i2c_client *client) +{ -+ struct ti964_ti9x3_priv *priv = i2c_get_clientdata(client); ++ struct ti9x4_priv *priv = i2c_get_clientdata(client); + int i; + + for (i = 0; i < priv->links; i++) { @@ -7411,39 +7605,39 @@ index 0000000..8393392 + return 0; +} + -+static const struct of_device_id ti964_ti9x3_dt_ids[] = { -+ { .compatible = "ti,ti964-ti9x3" }, ++static const struct of_device_id ti9x4_dt_ids[] = { ++ { .compatible = "ti,ti9x4" }, + {}, +}; -+MODULE_DEVICE_TABLE(of, ti964_ti9x3_dt_ids); ++MODULE_DEVICE_TABLE(of, ti9x4_dt_ids); + -+static const struct i2c_device_id ti964_ti9x3_id[] = { -+ { "ti964_ti9x3", 0 }, ++static const struct i2c_device_id ti9x4_id[] = { ++ { "ti9x4", 0 }, + { } +}; -+MODULE_DEVICE_TABLE(i2c, ti964_ti9x3_id); ++MODULE_DEVICE_TABLE(i2c, ti9x4_id); + -+static struct i2c_driver ti964_ti9x3_i2c_driver = { ++static struct i2c_driver ti9x4_i2c_driver = { + .driver = { -+ .name = "ti964_ti9x3", -+ .of_match_table = of_match_ptr(ti964_ti9x3_dt_ids), ++ .name = "ti9x4", ++ .of_match_table = of_match_ptr(ti9x4_dt_ids), + }, -+ .probe = ti964_ti9x3_probe, -+ .remove = ti964_ti9x3_remove, -+ .id_table = ti964_ti9x3_id, ++ .probe = ti9x4_probe, ++ .remove = ti9x4_remove, ++ .id_table = ti9x4_id, +}; + -+module_i2c_driver(ti964_ti9x3_i2c_driver); ++module_i2c_driver(ti9x4_i2c_driver); + -+MODULE_DESCRIPTION("FPDLinkIII driver for TI964-TI9X3"); ++MODULE_DESCRIPTION("FPDLinkIII driver for DS90UB9x4"); +MODULE_AUTHOR("Vladimir Barinov"); +MODULE_LICENSE("GPL"); -diff --git a/drivers/media/i2c/soc_camera/ti9x4_ti9x3.h b/drivers/media/i2c/soc_camera/ti9x4_ti9x3.h +diff --git a/drivers/media/i2c/soc_camera/ti9x4.h b/drivers/media/i2c/soc_camera/ti9x4.h new file mode 100644 -index 0000000..69d3728 +index 0000000..b53b4c6 --- /dev/null -+++ b/drivers/media/i2c/soc_camera/ti9x4_ti9x3.h -@@ -0,0 +1,153 @@ ++++ b/drivers/media/i2c/soc_camera/ti9x4.h +@@ -0,0 +1,156 @@ +/* + * TI FPDLinkIII driver include file + * @@ -7465,6 +7659,9 @@ index 0000000..69d3728 +#endif + +#define MAXIM_NUM_RETRIES 1 /* number of read/write retries */ ++#define TI913_ID 0x58 ++#define TI953_ID 0x30 /* or starapped to 0x32 */ ++#define TI9X4_ID 0x00 /* strapped */ +#define BROADCAST 0x6f + +static inline int reg8_read(struct i2c_client *client, u8 reg, u8 *val) @@ -8084,7 +8281,7 @@ index 4d95da6..2ef27e8 100644 return 0; diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c -index 74fb005..ac75af6 100644 +index 74fb005..f6119e5 100644 --- a/drivers/media/platform/soc_camera/rcar_vin.c +++ b/drivers/media/platform/soc_camera/rcar_vin.c @@ -95,17 +95,21 @@ @@ -8249,7 +8446,7 @@ index 74fb005..ac75af6 100644 while (priv->state != STOPPED) { /* issue stop if running */ if (priv->state == RUNNING) -@@ -1361,6 +1422,31 @@ static struct v4l2_subdev *find_csi2(struct rcar_vin_priv *pcdev) +@@ -1361,6 +1422,26 @@ static struct v4l2_subdev *find_csi2(struct rcar_vin_priv *pcdev) return NULL; } @@ -8257,8 +8454,7 @@ index 74fb005..ac75af6 100644 +{ + struct v4l2_subdev *sd; + char name[] = "max9286"; -+ char name2[] = "ti964_ti9x3"; -+ char name3[] = "ti954_ti9x3"; ++ char name2[] = "ti9x4"; + + v4l2_device_for_each_subdev(sd, &pcdev->ici.v4l2_dev) { + if (!strncmp(name, sd->name, sizeof(name) - 1)) { @@ -8269,10 +8465,6 @@ index 74fb005..ac75af6 100644 + pcdev->deser_sd = sd; + return sd; + } -+ if (!strncmp(name3, sd->name, sizeof(name3) - 1)) { -+ pcdev->deser_sd = sd; -+ return sd; -+ } + } + + return NULL; @@ -8281,7 +8473,7 @@ index 74fb005..ac75af6 100644 static int rcar_vin_add_device(struct soc_camera_device *icd) { struct soc_camera_host *ici = to_soc_camera_host(icd->parent); -@@ -1375,7 +1461,8 @@ static int rcar_vin_add_device(struct soc_camera_device *icd) +@@ -1375,7 +1456,8 @@ static int rcar_vin_add_device(struct soc_camera_device *icd) if (priv->chip == RCAR_H3 || priv->chip == RCAR_M3 || priv->chip == RCAR_V3M) { struct v4l2_subdev *csi2_sd = find_csi2(priv); @@ -8291,7 +8483,7 @@ index 74fb005..ac75af6 100644 if (csi2_sd) { csi2_sd->grp_id = soc_camera_grp_id(icd); -@@ -1390,6 +1477,18 @@ static int rcar_vin_add_device(struct soc_camera_device *icd) +@@ -1390,6 +1472,18 @@ static int rcar_vin_add_device(struct soc_camera_device *icd) if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) return ret; } @@ -8310,7 +8502,7 @@ index 74fb005..ac75af6 100644 /* * -ENODEV is special: * either csi2_sd == NULL or the CSI-2 driver -@@ -1417,6 +1516,7 @@ static void rcar_vin_remove_device(struct soc_camera_device *icd) +@@ -1417,6 +1511,7 @@ static void rcar_vin_remove_device(struct soc_camera_device *icd) struct rcar_vin_priv *priv = ici->priv; struct vb2_v4l2_buffer *vbuf; struct v4l2_subdev *csi2_sd = find_csi2(priv); @@ -8318,7 +8510,7 @@ index 74fb005..ac75af6 100644 int i; /* disable capture, disable interrupts */ -@@ -1443,6 +1543,8 @@ static void rcar_vin_remove_device(struct soc_camera_device *icd) +@@ -1443,6 +1538,8 @@ static void rcar_vin_remove_device(struct soc_camera_device *icd) if ((csi2_sd) && (priv->csi_sync)) v4l2_subdev_call(csi2_sd, core, s_power, 0); @@ -8327,7 +8519,7 @@ index 74fb005..ac75af6 100644 dev_dbg(icd->parent, "R-Car VIN driver detached from camera %d\n", icd->devnum); -@@ -1621,13 +1723,19 @@ static int rcar_vin_set_rect(struct soc_camera_device *icd) +@@ -1621,13 +1718,19 @@ static int rcar_vin_set_rect(struct soc_camera_device *icd) if (priv->chip == RCAR_H3 || priv->chip == RCAR_M3 || priv->chip == RCAR_V3M) { @@ -8349,7 +8541,7 @@ index 74fb005..ac75af6 100644 (icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_NV16) || (icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_NV12)) iowrite32(ALIGN(cam->out_width, 0x20), -@@ -1868,6 +1976,14 @@ static bool rcar_vin_packing_supported(const struct soc_mbus_pixelfmt *fmt) +@@ -1868,6 +1971,14 @@ static bool rcar_vin_packing_supported(const struct soc_mbus_pixelfmt *fmt) .layout = SOC_MBUS_LAYOUT_PACKED, }, { @@ -8364,7 +8556,7 @@ index 74fb005..ac75af6 100644 .fourcc = V4L2_PIX_FMT_RGB565, .name = "RGB565", .bits_per_sample = 16, -@@ -1899,6 +2015,22 @@ static bool rcar_vin_packing_supported(const struct soc_mbus_pixelfmt *fmt) +@@ -1899,6 +2010,22 @@ static bool rcar_vin_packing_supported(const struct soc_mbus_pixelfmt *fmt) .order = SOC_MBUS_ORDER_LE, .layout = SOC_MBUS_LAYOUT_PACKED, }, @@ -8387,7 +8579,7 @@ index 74fb005..ac75af6 100644 }; static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx, -@@ -2012,6 +2144,8 @@ static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx, +@@ -2012,6 +2139,8 @@ static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx, case MEDIA_BUS_FMT_YUYV8_2X8: case MEDIA_BUS_FMT_YUYV10_2X10: case MEDIA_BUS_FMT_RGB888_1X24: @@ -8396,7 +8588,7 @@ index 74fb005..ac75af6 100644 if (cam->extra_fmt) break; -@@ -2218,12 +2352,15 @@ static int rcar_vin_set_fmt(struct soc_camera_device *icd, +@@ -2218,12 +2347,15 @@ static int rcar_vin_set_fmt(struct soc_camera_device *icd, case V4L2_PIX_FMT_ABGR32: case V4L2_PIX_FMT_UYVY: case V4L2_PIX_FMT_YUYV: @@ -8412,7 +8604,7 @@ index 74fb005..ac75af6 100644 default: can_scale = false; break; -@@ -2316,7 +2453,8 @@ static int rcar_vin_try_fmt(struct soc_camera_device *icd, +@@ -2316,7 +2448,8 @@ static int rcar_vin_try_fmt(struct soc_camera_device *icd, /* odd number clipping by pixel post clip processing, */ /* it is outputted to a memory per even pixels. */ if ((pixfmt == V4L2_PIX_FMT_NV16) || (pixfmt == V4L2_PIX_FMT_NV12) || @@ -8422,7 +8614,7 @@ index 74fb005..ac75af6 100644 v4l_bound_align_image(&pix->width, 5, priv->max_width, 1, &pix->height, 2, priv->max_height, 0, 0); else -@@ -2486,6 +2624,19 @@ static int rcar_vin_cropcap(struct soc_camera_device *icd, +@@ -2486,6 +2619,19 @@ static int rcar_vin_cropcap(struct soc_camera_device *icd, } #endif @@ -8442,7 +8634,7 @@ index 74fb005..ac75af6 100644 static struct soc_camera_host_ops rcar_vin_host_ops = { .owner = THIS_MODULE, .add = rcar_vin_add_device, -@@ -2504,6 +2655,7 @@ static int rcar_vin_cropcap(struct soc_camera_device *icd, +@@ -2504,6 +2650,7 @@ static int rcar_vin_cropcap(struct soc_camera_device *icd, .get_selection = rcar_vin_get_selection, .cropcap = rcar_vin_cropcap, #endif @@ -8450,7 +8642,7 @@ index 74fb005..ac75af6 100644 }; #ifdef CONFIG_OF -@@ -2524,7 +2676,7 @@ static int rcar_vin_cropcap(struct soc_camera_device *icd, +@@ -2524,7 +2671,7 @@ static int rcar_vin_cropcap(struct soc_camera_device *icd, MODULE_DEVICE_TABLE(of, rcar_vin_of_table); #endif @@ -8459,19 +8651,18 @@ index 74fb005..ac75af6 100644 static DECLARE_BITMAP(device_map, MAP_MAX_NUM); static DEFINE_MUTEX(list_lock); -@@ -2714,7 +2866,11 @@ static int rcar_vin_probe(struct platform_device *pdev) +@@ -2714,7 +2861,10 @@ static int rcar_vin_probe(struct platform_device *pdev) const char *str; unsigned int i; struct device_node *epn = NULL, *ren = NULL; -+ struct device_node *csi2_ren = NULL, *max9286_ren = NULL, *ti964_ren = NULL, *ti954_ren = NULL; ++ struct device_node *csi2_ren = NULL, *max9286_ren = NULL, *ti9x4_ren = NULL; bool csi_use = false; + bool max9286_use = false; -+ bool ti964_use = false; -+ bool ti954_use = false; ++ bool ti9x4_use = false; match = of_match_device(of_match_ptr(rcar_vin_of_table), &pdev->dev); -@@ -2741,13 +2897,27 @@ static int rcar_vin_probe(struct platform_device *pdev) +@@ -2741,13 +2891,22 @@ static int rcar_vin_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "node name:%s\n", of_node_full_name(ren->parent)); @@ -8489,21 +8680,16 @@ index 74fb005..ac75af6 100644 - if (i) - break; -+ if (strcmp(ren->parent->name, "ti964-ti9x3") == 0) { -+ ti964_ren = of_parse_phandle(epn, "remote-endpoint", 0); -+ ti964_use = true; -+ } -+ -+ if (strcmp(ren->parent->name, "ti954-ti9x3") == 0) { -+ ti954_ren = of_parse_phandle(epn, "remote-endpoint", 0); -+ ti954_use = true; ++ if (strcmp(ren->parent->name, "ti9x4") == 0) { ++ ti9x4_ren = of_parse_phandle(epn, "remote-endpoint", 0); ++ ti9x4_use = true; + } + + of_node_put(ren); } ret = v4l2_of_parse_endpoint(np, &ep); -@@ -2799,6 +2969,7 @@ static int rcar_vin_probe(struct platform_device *pdev) +@@ -2799,6 +2958,7 @@ static int rcar_vin_probe(struct platform_device *pdev) priv->ici.drv_name = dev_name(&pdev->dev); priv->ici.ops = &rcar_vin_host_ops; priv->csi_sync = false; @@ -8511,7 +8697,7 @@ index 74fb005..ac75af6 100644 priv->pdata_flags = pdata_flags; if (!match) { -@@ -2983,7 +3154,25 @@ static int rcar_vin_probe(struct platform_device *pdev) +@@ -2983,7 +3143,19 @@ static int rcar_vin_probe(struct platform_device *pdev) goto cleanup; if (csi_use) { @@ -8527,14 +8713,8 @@ index 74fb005..ac75af6 100644 + goto cleanup; + } + -+ if (ti964_use) { -+ ret = rcar_vin_soc_of_bind(priv, &priv->ici, epn, ti964_ren); -+ if (ret) -+ goto cleanup; -+ } -+ -+ if (ti954_use) { -+ ret = rcar_vin_soc_of_bind(priv, &priv->ici, epn, ti954_ren); ++ if (ti9x4_use) { ++ ret = rcar_vin_soc_of_bind(priv, &priv->ici, epn, ti9x4_ren); if (ret) goto cleanup; } diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0040-arm64-dts-renesas-add-ADAS-boards.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0040-arm64-dts-renesas-add-ADAS-boards.patch index 7755871..b351089 100644 --- a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0040-arm64-dts-renesas-add-ADAS-boards.patch +++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0040-arm64-dts-renesas-add-ADAS-boards.patch @@ -21,6 +21,7 @@ Eagle board on R8A7797 SoC Eagle Function board on R8A7797 SoC V3MSK board on R8A7797 SoC V3MSK.View board on R8A7797 SoC +V3MZF board on R8A7797 SoC Videobox Mini board on R8A7795 ES1.x SoC Videobox Mini board on R8A7795 SoC Videobox Mini board on R8A7797 SoC @@ -30,14 +31,14 @@ Condor board on R8A7798 SoC Signed-off-by: Vladimir Barinov --- - arch/arm64/boot/dts/renesas/Makefile | 21 + + arch/arm64/boot/dts/renesas/Makefile | 22 + arch/arm64/boot/dts/renesas/legacy/Makefile | 8 + - .../renesas/legacy/r8a7795-es1-h3ulcb-kf-v0.dts | 1710 ++++++++++++++++++ + .../renesas/legacy/r8a7795-es1-h3ulcb-kf-v0.dts | 1624 ++++++++++++++++++ .../renesas/legacy/r8a7795-es1-h3ulcb-kf-v1.dts | 441 +++++ - .../dts/renesas/legacy/r8a7795-h3ulcb-kf-v0.dts | 1724 ++++++++++++++++++ - .../dts/renesas/legacy/r8a7795-h3ulcb-kf-v1.dts | 465 +++++ - .../dts/renesas/legacy/r8a7796-m3ulcb-kf-v0.dts | 1214 +++++++++++++ - .../dts/renesas/legacy/r8a7796-m3ulcb-kf-v1.dts | 465 +++++ + .../dts/renesas/legacy/r8a7795-h3ulcb-kf-v0.dts | 1638 +++++++++++++++++++ + .../dts/renesas/legacy/r8a7795-h3ulcb-kf-v1.dts | 465 ++++++ + .../dts/renesas/legacy/r8a7796-m3ulcb-kf-v0.dts | 1171 +++++++++++++ + .../dts/renesas/legacy/r8a7796-m3ulcb-kf-v1.dts | 465 ++++++ .../dts/renesas/legacy/r8a7797-v3msk-kf-v0.dts | 82 + .../boot/dts/renesas/legacy/ulcb-kf-cmos.dtsi | 75 + .../arm64/boot/dts/renesas/legacy/ulcb-kf-rpi.dtsi | 77 + @@ -49,7 +50,7 @@ Signed-off-by: Vladimir Barinov .../boot/dts/renesas/r8a7795-es1-h3ulcb-vb2.dts | 77 + .../boot/dts/renesas/r8a7795-es1-h3ulcb-vbm.dts | 26 + .../boot/dts/renesas/r8a7795-es1-h3ulcb-view.dts | 544 ++++++ - .../dts/renesas/r8a7795-es1-salvator-x-view.dts | 550 ++++++ + .../dts/renesas/r8a7795-es1-salvator-x-view.dts | 550 +++++++ .../boot/dts/renesas/r8a7795-h3ulcb-had-alfa.dts | 22 + .../boot/dts/renesas/r8a7795-h3ulcb-had-beta.dts | 23 + .../arm64/boot/dts/renesas/r8a7795-h3ulcb-had.dtsi | 215 +++ @@ -58,26 +59,27 @@ Signed-off-by: Vladimir Barinov arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vb2.dts | 68 + arch/arm64/boot/dts/renesas/r8a7795-h3ulcb-vbm.dts | 26 + .../arm64/boot/dts/renesas/r8a7795-h3ulcb-view.dts | 544 ++++++ - .../boot/dts/renesas/r8a7795-salvator-x-view.dts | 550 ++++++ + .../boot/dts/renesas/r8a7795-salvator-x-view.dts | 550 +++++++ arch/arm64/boot/dts/renesas/r8a7796-m3ulcb-kf.dts | 40 + - .../arm64/boot/dts/renesas/r8a7796-m3ulcb-view.dts | 286 +++ + .../arm64/boot/dts/renesas/r8a7796-m3ulcb-view.dts | 286 ++++ .../boot/dts/renesas/r8a7796-salvator-x-view.dts | 317 ++++ .../boot/dts/renesas/r8a7797-eagle-function.dts | 62 + arch/arm64/boot/dts/renesas/r8a7797-eagle.dts | 575 +++++++ - arch/arm64/boot/dts/renesas/r8a7797-v3msk-kf.dts | 575 +++++++ - arch/arm64/boot/dts/renesas/r8a7797-v3msk-vbm.dts | 548 ++++++ + arch/arm64/boot/dts/renesas/r8a7797-v3msk-kf.dts | 533 ++++++ + arch/arm64/boot/dts/renesas/r8a7797-v3msk-vbm.dts | 548 +++++++ arch/arm64/boot/dts/renesas/r8a7797-v3msk-view.dts | 297 ++++ arch/arm64/boot/dts/renesas/r8a7797-v3msk.dts | 314 ++++ + arch/arm64/boot/dts/renesas/r8a7797-v3mzf.dts | 424 +++++ arch/arm64/boot/dts/renesas/r8a7798-condor.dts | 963 +++++++++++ - arch/arm64/boot/dts/renesas/ulcb-kf-cn11.dtsi | 545 ++++++ + arch/arm64/boot/dts/renesas/ulcb-kf-cn11.dtsi | 498 ++++++ arch/arm64/boot/dts/renesas/ulcb-kf-most.dtsi | 30 + arch/arm64/boot/dts/renesas/ulcb-kf-sd3.dtsi | 46 + - arch/arm64/boot/dts/renesas/ulcb-kf.dtsi | 1538 +++++++++++++++++ - arch/arm64/boot/dts/renesas/ulcb-vb-cn12.dtsi | 542 ++++++ - arch/arm64/boot/dts/renesas/ulcb-vb.dtsi | 1770 +++++++++++++++++++ - arch/arm64/boot/dts/renesas/ulcb-vb2.dtsi | 1820 ++++++++++++++++++++ + arch/arm64/boot/dts/renesas/ulcb-kf.dtsi | 1492 +++++++++++++++++ + arch/arm64/boot/dts/renesas/ulcb-vb-cn12.dtsi | 495 ++++++ + arch/arm64/boot/dts/renesas/ulcb-vb.dtsi | 1678 +++++++++++++++++++ + arch/arm64/boot/dts/renesas/ulcb-vb2.dtsi | 1724 ++++++++++++++++++++ arch/arm64/boot/dts/renesas/ulcb-vbm.dtsi | 577 +++++++ - 47 files changed, 20253 insertions(+) + 48 files changed, 20093 insertions(+) create mode 100644 arch/arm64/boot/dts/renesas/legacy/Makefile create mode 100644 arch/arm64/boot/dts/renesas/legacy/r8a7795-es1-h3ulcb-kf-v0.dts create mode 100644 arch/arm64/boot/dts/renesas/legacy/r8a7795-es1-h3ulcb-kf-v1.dts @@ -115,6 +117,7 @@ Signed-off-by: Vladimir Barinov create mode 100644 arch/arm64/boot/dts/renesas/r8a7797-v3msk-vbm.dts create mode 100644 arch/arm64/boot/dts/renesas/r8a7797-v3msk-view.dts create mode 100644 arch/arm64/boot/dts/renesas/r8a7797-v3msk.dts + create mode 100644 arch/arm64/boot/dts/renesas/r8a7797-v3mzf.dts create mode 100644 arch/arm64/boot/dts/renesas/r8a7798-condor.dts create mode 100644 arch/arm64/boot/dts/renesas/ulcb-kf-cn11.dtsi create mode 100644 arch/arm64/boot/dts/renesas/ulcb-kf-most.dtsi @@ -126,10 +129,10 @@ Signed-off-by: Vladimir Barinov create mode 100644 arch/arm64/boot/dts/renesas/ulcb-vbm.dtsi diff --git a/arch/arm64/boot/dts/renesas/Makefile b/arch/arm64/boot/dts/renesas/Makefile -index f9c71df..3b5cff6 100644 +index f9c71df..6ca2c60 100644 --- a/arch/arm64/boot/dts/renesas/Makefile +++ b/arch/arm64/boot/dts/renesas/Makefile -@@ -6,5 +6,26 @@ dtb-$(CONFIG_ARCH_R8A7796) += r8a7796-salvator-xs.dtb +@@ -6,5 +6,27 @@ dtb-$(CONFIG_ARCH_R8A7796) += r8a7796-salvator-xs.dtb dtb-$(CONFIG_ARCH_R8A77965) += r8a77965-salvator-x.dtb dtb-$(CONFIG_ARCH_R8A77965) += r8a77965-salvator-xs.dtb @@ -149,6 +152,7 @@ index f9c71df..3b5cff6 100644 +dtb-$(CONFIG_ARCH_R8A7797) += r8a7797-v3msk-view.dtb +dtb-$(CONFIG_ARCH_R8A7797) += r8a7797-v3msk-kf.dtb +dtb-$(CONFIG_ARCH_R8A7797) += r8a7797-v3msk-vbm.dtb ++dtb-$(CONFIG_ARCH_R8A7797) += r8a7797-v3mzf.dtb +dtb-$(CONFIG_ARCH_R8A7798) += r8a7798-condor.dtb + +# ADAS legacy boards @@ -172,10 +176,10 @@ index 0000000..7f25079 +clean-files := *.dtb diff --git a/arch/arm64/boot/dts/renesas/legacy/r8a7795-es1-h3ulcb-kf-v0.dts b/arch/arm64/boot/dts/renesas/legacy/r8a7795-es1-h3ulcb-kf-v0.dts new file mode 100644 -index 0000000..fe07e22 +index 0000000..01aef82 --- /dev/null +++ b/arch/arm64/boot/dts/renesas/legacy/r8a7795-es1-h3ulcb-kf-v0.dts -@@ -0,0 +1,1710 @@ +@@ -0,0 +1,1624 @@ +/* + * Device Tree Source for the H3ULCB Kingfisher V0 board on r8a7795 ES1.x + * @@ -764,11 +768,8 @@ index 0000000..fe07e22 + ov106xx_max9286_des0ep0: endpoint@0 { + remote-endpoint = <&max9286_des0ep0>; + }; -+ ov106xx_ti964_des0ep0: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep0>; -+ }; -+ ov106xx_ti954_des0ep0: endpoint@2 { -+ remote-endpoint = <&ti954_des0ep0>; ++ ov106xx_ti9x4_des0ep0: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep0>; + }; + }; + }; @@ -788,11 +789,8 @@ index 0000000..fe07e22 + ov106xx_max9286_des0ep1: endpoint@0 { + remote-endpoint = <&max9286_des0ep1>; + }; -+ ov106xx_ti964_des0ep1: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep1>; -+ }; -+ ov106xx_ti954_des0ep1: endpoint@2 { -+ remote-endpoint = <&ti954_des0ep1>; ++ ov106xx_ti9x4_des0ep1: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep1>; + }; + }; + }; @@ -812,8 +810,8 @@ index 0000000..fe07e22 + ov106xx_max9286_des0ep2: endpoint@0 { + remote-endpoint = <&max9286_des0ep2>; + }; -+ ov106xx_ti964_des0ep2: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep2>; ++ ov106xx_ti9x4_des0ep2: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep2>; + }; + }; + }; @@ -833,15 +831,15 @@ index 0000000..fe07e22 + ov106xx_max9286_des0ep3: endpoint@0 { + remote-endpoint = <&max9286_des0ep3>; + }; -+ ov106xx_ti964_des0ep3: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep3>; ++ ov106xx_ti9x4_des0ep3: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep3>; + }; + }; + }; + -+ /* DS90UB964 @ 0x3a */ -+ ti964-ti9x3@0 { -+ compatible = "ti,ti964-ti9x3"; ++ /* DS90UB9x4 @ 0x3a */ ++ ti9x4@0 { ++ compatible = "ti,ti9x4"; + reg = <0x3a>; + ti,sensor_delay = <350>; + ti,links = <4>; @@ -850,60 +848,29 @@ index 0000000..fe07e22 + ti,cable-mode = "coax"; + + port@0 { -+ ti964_des0ep0: endpoint@0 { ++ ti9x4_des0ep0: endpoint@0 { + ti9x3-addr = <0x0c>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in0>; + }; -+ ti964_des0ep1: endpoint@1 { ++ ti9x4_des0ep1: endpoint@1 { + ti9x3-addr = <0x0d>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in1>; + }; -+ ti964_des0ep2: endpoint@2 { ++ ti9x4_des0ep2: endpoint@2 { + ti9x3-addr = <0x0e>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in2>; + }; -+ ti964_des0ep3: endpoint@3 { ++ ti9x4_des0ep3: endpoint@3 { + ti9x3-addr = <0x0f>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in3>; + }; + }; + port@1 { -+ ti964_csi0ep0: endpoint { -+ csi-rate = <1450>; -+ remote-endpoint = <&csi2_40_ep>; -+ }; -+ }; -+ }; -+ -+ /* DS90UB954 @ 0x38 */ -+ ti954-ti9x3@0 { -+ compatible = "ti,ti954-ti9x3"; -+ reg = <0x38>; -+ /* gpios = <&video_a_ext1 10 GPIO_ACTIVE_HIGH>; */ -+ ti,sensor_delay = <350>; -+ ti,links = <2>; -+ ti,lanes = <4>; -+ ti,forwarding-mode = "round-robin"; -+ ti,cable-mode = "coax"; -+ -+ port@0 { -+ ti954_des0ep0: endpoint@0 { -+ ti9x3-addr = <0x0c>; -+ dvp-order = <0>; -+ remote-endpoint = <&ov106xx_in0>; -+ }; -+ ti954_des0ep1: endpoint@1 { -+ ti9x3-addr = <0x0d>; -+ dvp-order = <0>; -+ remote-endpoint = <&ov106xx_in1>; -+ }; -+ }; -+ port@1 { -+ ti954_csi0ep0: endpoint { ++ ti9x4_csi0ep0: endpoint { + csi-rate = <1450>; + remote-endpoint = <&csi2_40_ep>; + }; @@ -973,11 +940,8 @@ index 0000000..fe07e22 + ov106xx_max9286_des1ep0: endpoint@0 { + remote-endpoint = <&max9286_des1ep0>; + }; -+ ov106xx_ti964_des1ep0: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep0>; -+ }; -+ ov106xx_ti954_des1ep0: endpoint@2 { -+ remote-endpoint = <&ti954_des1ep0>; ++ ov106xx_ti9x4_des1ep0: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep0>; + }; + }; + }; @@ -997,11 +961,8 @@ index 0000000..fe07e22 + ov106xx_max9286_des1ep1: endpoint@0 { + remote-endpoint = <&max9286_des1ep1>; + }; -+ ov106xx_ti964_des1ep1: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep1>; -+ }; -+ ov106xx_ti954_des1ep1: endpoint@2 { -+ remote-endpoint = <&ti954_des1ep1>; ++ ov106xx_ti9x4_des1ep1: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep1>; + }; + }; + }; @@ -1021,8 +982,8 @@ index 0000000..fe07e22 + ov106xx_max9286_des1ep2: endpoint@0 { + remote-endpoint = <&max9286_des1ep2>; + }; -+ ov106xx_ti964_des1ep2: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep2>; ++ ov106xx_ti9x4_des1ep2: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep2>; + }; + }; + }; @@ -1042,15 +1003,15 @@ index 0000000..fe07e22 + ov106xx_max9286_des1ep3: endpoint@0 { + remote-endpoint = <&max9286_des1ep3>; + }; -+ ov106xx_ti964_des1ep3: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep3>; ++ ov106xx_ti9x4_des1ep3: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep3>; + }; + }; + }; + -+ /* DS90UB964 @ 0x3a */ -+ ti964-ti9x3@1 { -+ compatible = "ti,ti964-ti9x3"; ++ /* DS90UB9x4 @ 0x3a */ ++ ti9x4@1 { ++ compatible = "ti,ti9x4"; + reg = <0x3a>; + ti,sensor_delay = <350>; + ti,links = <4>; @@ -1059,60 +1020,29 @@ index 0000000..fe07e22 + ti,cable-mode = "coax"; + + port@0 { -+ ti964_des1ep0: endpoint@0 { ++ ti9x4_des1ep0: endpoint@0 { + ti9x3-addr = <0x0c>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in4>; + }; -+ ti964_des1ep1: endpoint@1 { ++ ti9x4_des1ep1: endpoint@1 { + ti9x3-addr = <0x0d>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in5>; + }; -+ ti964_des1ep2: endpoint@2 { ++ ti9x4_des1ep2: endpoint@2 { + ti9x3-addr = <0x0e>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in6>; + }; -+ ti964_des1ep3: endpoint@3 { ++ ti9x4_des1ep3: endpoint@3 { + ti9x3-addr = <0x0f>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in7>; + }; + }; + port@1 { -+ ti964_csi2ep0: endpoint { -+ csi-rate = <1450>; -+ remote-endpoint = <&csi2_41_ep>; -+ }; -+ }; -+ }; -+ -+ /* DS90UB954 @ 0x38 */ -+ ti954-ti9x3@1 { -+ compatible = "ti,ti954-ti9x3"; -+ reg = <0x38>; -+ /* gpios = <&video_b_ext1 10 GPIO_ACTIVE_HIGH>; */ -+ ti,sensor_delay = <350>; -+ ti,links = <2>; -+ ti,lanes = <4>; -+ ti,forwarding-mode = "round-robin"; -+ ti,cable-mode = "coax"; -+ -+ port@0 { -+ ti954_des1ep0: endpoint@0 { -+ ti9x3-addr = <0x0c>; -+ dvp-order = <0>; -+ remote-endpoint = <&ov106xx_in4>; -+ }; -+ ti954_des1ep1: endpoint@1 { -+ ti9x3-addr = <0x0d>; -+ dvp-order = <0>; -+ remote-endpoint = <&ov106xx_in5>; -+ }; -+ }; -+ port@1 { -+ ti954_csi2ep0: endpoint { ++ ti9x4_csi2ep0: endpoint { + csi-rate = <1450>; + remote-endpoint = <&csi2_41_ep>; + }; @@ -1474,11 +1404,8 @@ index 0000000..fe07e22 + vin0_max9286_des0ep0: endpoint@0 { + remote-endpoint = <&max9286_des0ep0>; + }; -+ vin0_ti964_des0ep0: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep0>; -+ }; -+ vin0_ti954_des0ep0: endpoint@2 { -+ remote-endpoint = <&ti954_des0ep0>; ++ vin0_ti9x4_des0ep0: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep0>; + }; + }; + }; @@ -1508,11 +1435,8 @@ index 0000000..fe07e22 + vin1_max9286_des0ep1: endpoint@0 { + remote-endpoint = <&max9286_des0ep1>; + }; -+ vin1_ti964_des0ep1: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep1>; -+ }; -+ vin1_ti954_des0ep1: endpoint@2 { -+ remote-endpoint = <&ti954_des0ep1>; ++ vin1_ti9x4_des0ep1: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep1>; + }; + }; + }; @@ -1542,8 +1466,8 @@ index 0000000..fe07e22 + vin2_max9286_des0ep2: endpoint@0 { + remote-endpoint = <&max9286_des0ep2>; + }; -+ vin2_ti964_des0ep2: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep2>; ++ vin2_ti9x4_des0ep2: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep2>; + }; + }; + }; @@ -1573,8 +1497,8 @@ index 0000000..fe07e22 + vin3_max9286_des0ep3: endpoint@0 { + remote-endpoint = <&max9286_des0ep3>; + }; -+ vin3_ti964_des0ep3: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep3>; ++ vin3_ti9x4_des0ep3: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep3>; + }; + }; + }; @@ -1604,11 +1528,8 @@ index 0000000..fe07e22 + vin4_max9286_des1ep0: endpoint@0 { + remote-endpoint = <&max9286_des1ep0>; + }; -+ vin4_ti964_des1ep0: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep0>; -+ }; -+ vin4_ti954_des1ep0: endpoint@2 { -+ remote-endpoint = <&ti954_des1ep0>; ++ vin4_ti9x4_des1ep0: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep0>; + }; + }; + }; @@ -1638,11 +1559,8 @@ index 0000000..fe07e22 + vin5_max9286_des1ep1: endpoint@0 { + remote-endpoint = <&max9286_des1ep1>; + }; -+ vin5_ti964_des1ep1: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep1>; -+ }; -+ vin5_ti954_des1ep1: endpoint@2 { -+ remote-endpoint = <&ti954_des1ep1>; ++ vin5_ti9x4_des1ep1: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep1>; + }; + }; + }; @@ -1672,8 +1590,8 @@ index 0000000..fe07e22 + vin6_max9286_des1ep2: endpoint@0 { + remote-endpoint = <&max9286_des1ep2>; + }; -+ vin6_ti964_des1ep2: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep2>; ++ vin6_ti9x4_des1ep2: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep2>; + }; + }; + }; @@ -1703,8 +1621,8 @@ index 0000000..fe07e22 + vin7_max9286_des1ep3: endpoint@0 { + remote-endpoint = <&max9286_des1ep3>; + }; -+ vin7_ti964_des1ep3: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep3>; ++ vin7_ti9x4_des1ep3: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep3>; + }; + }; + }; @@ -2335,10 +2253,10 @@ index 0000000..ac6a12b +}; diff --git a/arch/arm64/boot/dts/renesas/legacy/r8a7795-h3ulcb-kf-v0.dts b/arch/arm64/boot/dts/renesas/legacy/r8a7795-h3ulcb-kf-v0.dts new file mode 100644 -index 0000000..c19bc58 +index 0000000..dd1aadc --- /dev/null +++ b/arch/arm64/boot/dts/renesas/legacy/r8a7795-h3ulcb-kf-v0.dts -@@ -0,0 +1,1724 @@ +@@ -0,0 +1,1638 @@ +/* + * Device Tree Source for the H3ULCB Kingfisher V0 board on r8a7795 + * @@ -2927,11 +2845,8 @@ index 0000000..c19bc58 + ov106xx_max9286_des0ep0: endpoint@0 { + remote-endpoint = <&max9286_des0ep0>; + }; -+ ov106xx_ti964_des0ep0: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep0>; -+ }; -+ ov106xx_ti954_des0ep0: endpoint@2 { -+ remote-endpoint = <&ti954_des0ep0>; ++ ov106xx_ti9x4_des0ep0: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep0>; + }; + }; + }; @@ -2951,11 +2866,8 @@ index 0000000..c19bc58 + ov106xx_max9286_des0ep1: endpoint@0 { + remote-endpoint = <&max9286_des0ep1>; + }; -+ ov106xx_ti964_des0ep1: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep1>; -+ }; -+ ov106xx_ti954_des0ep1: endpoint@2 { -+ remote-endpoint = <&ti954_des0ep1>; ++ ov106xx_ti9x4_des0ep1: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep1>; + }; + }; + }; @@ -2975,8 +2887,8 @@ index 0000000..c19bc58 + ov106xx_max9286_des0ep2: endpoint@0 { + remote-endpoint = <&max9286_des0ep2>; + }; -+ ov106xx_ti964_des0ep2: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep2>; ++ ov106xx_ti9x4_des0ep2: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep2>; + }; + }; + }; @@ -2996,15 +2908,15 @@ index 0000000..c19bc58 + ov106xx_max9286_des0ep3: endpoint@0 { + remote-endpoint = <&max9286_des0ep3>; + }; -+ ov106xx_ti964_des0ep3: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep3>; ++ ov106xx_ti9x4_des0ep3: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep3>; + }; + }; + }; + -+ /* DS90UB964 @ 0x3a */ -+ ti964-ti9x3@0 { -+ compatible = "ti,ti964-ti9x3"; ++ /* DS90UB9x4 @ 0x3a */ ++ ti9x4@0 { ++ compatible = "ti,ti9x4"; + reg = <0x3a>; + ti,sensor_delay = <350>; + ti,links = <4>; @@ -3013,60 +2925,29 @@ index 0000000..c19bc58 + ti,cable-mode = "coax"; + + port@0 { -+ ti964_des0ep0: endpoint@0 { ++ ti9x4_des0ep0: endpoint@0 { + ti9x3-addr = <0x0c>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in0>; + }; -+ ti964_des0ep1: endpoint@1 { ++ ti9x4_des0ep1: endpoint@1 { + ti9x3-addr = <0x0d>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in1>; + }; -+ ti964_des0ep2: endpoint@2 { ++ ti9x4_des0ep2: endpoint@2 { + ti9x3-addr = <0x0e>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in2>; + }; -+ ti964_des0ep3: endpoint@3 { ++ ti9x4_des0ep3: endpoint@3 { + ti9x3-addr = <0x0f>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in3>; + }; + }; + port@1 { -+ ti964_csi0ep0: endpoint { -+ csi-rate = <1450>; -+ remote-endpoint = <&csi2_40_ep>; -+ }; -+ }; -+ }; -+ -+ /* DS90UB954 @ 0x38 */ -+ ti954-ti9x3@0 { -+ compatible = "ti,ti954-ti9x3"; -+ reg = <0x38>; -+ /* gpios = <&video_a_ext1 10 GPIO_ACTIVE_HIGH>; */ -+ ti,sensor_delay = <350>; -+ ti,links = <2>; -+ ti,lanes = <4>; -+ ti,forwarding-mode = "round-robin"; -+ ti,cable-mode = "coax"; -+ -+ port@0 { -+ ti954_des0ep0: endpoint@0 { -+ ti9x3-addr = <0x0c>; -+ dvp-order = <0>; -+ remote-endpoint = <&ov106xx_in0>; -+ }; -+ ti954_des0ep1: endpoint@1 { -+ ti9x3-addr = <0x0d>; -+ dvp-order = <0>; -+ remote-endpoint = <&ov106xx_in1>; -+ }; -+ }; -+ port@1 { -+ ti954_csi0ep0: endpoint { ++ ti9x4_csi0ep0: endpoint { + csi-rate = <1450>; + remote-endpoint = <&csi2_40_ep>; + }; @@ -3136,11 +3017,8 @@ index 0000000..c19bc58 + ov106xx_max9286_des1ep0: endpoint@0 { + remote-endpoint = <&max9286_des1ep0>; + }; -+ ov106xx_ti964_des1ep0: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep0>; -+ }; -+ ov106xx_ti954_des1ep0: endpoint@2 { -+ remote-endpoint = <&ti954_des1ep0>; ++ ov106xx_ti9x4_des1ep0: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep0>; + }; + }; + }; @@ -3160,11 +3038,8 @@ index 0000000..c19bc58 + ov106xx_max9286_des1ep1: endpoint@0 { + remote-endpoint = <&max9286_des1ep1>; + }; -+ ov106xx_ti964_des1ep1: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep1>; -+ }; -+ ov106xx_ti954_des1ep1: endpoint@2 { -+ remote-endpoint = <&ti954_des1ep1>; ++ ov106xx_ti9x4_des1ep1: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep1>; + }; + }; + }; @@ -3184,8 +3059,8 @@ index 0000000..c19bc58 + ov106xx_max9286_des1ep2: endpoint@0 { + remote-endpoint = <&max9286_des1ep2>; + }; -+ ov106xx_ti964_des1ep2: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep2>; ++ ov106xx_ti9x4_des1ep2: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep2>; + }; + }; + }; @@ -3205,15 +3080,15 @@ index 0000000..c19bc58 + ov106xx_max9286_des1ep3: endpoint@0 { + remote-endpoint = <&max9286_des1ep3>; + }; -+ ov106xx_ti964_des1ep3: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep3>; ++ ov106xx_ti9x4_des1ep3: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep3>; + }; + }; + }; + -+ /* DS90UB964 @ 0x3a */ -+ ti964-ti9x3@1 { -+ compatible = "ti,ti964-ti9x3"; ++ /* DS90UB9x4 @ 0x3a */ ++ ti9x4@1 { ++ compatible = "ti,ti9x4"; + reg = <0x3a>; + ti,sensor_delay = <350>; + ti,links = <4>; @@ -3222,60 +3097,29 @@ index 0000000..c19bc58 + ti,cable-mode = "coax"; + + port@0 { -+ ti964_des1ep0: endpoint@0 { ++ ti9x4_des1ep0: endpoint@0 { + ti9x3-addr = <0x0c>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in4>; + }; -+ ti964_des1ep1: endpoint@1 { ++ ti9x4_des1ep1: endpoint@1 { + ti9x3-addr = <0x0d>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in5>; + }; -+ ti964_des1ep2: endpoint@2 { ++ ti9x4_des1ep2: endpoint@2 { + ti9x3-addr = <0x0e>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in6>; + }; -+ ti964_des1ep3: endpoint@3 { ++ ti9x4_des1ep3: endpoint@3 { + ti9x3-addr = <0x0f>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in7>; + }; + }; + port@1 { -+ ti964_csi2ep0: endpoint { -+ csi-rate = <1450>; -+ remote-endpoint = <&csi2_41_ep>; -+ }; -+ }; -+ }; -+ -+ /* DS90UB954 @ 0x38 */ -+ ti954-ti9x3@1 { -+ compatible = "ti,ti954-ti9x3"; -+ reg = <0x38>; -+ /* gpios = <&video_b_ext1 10 GPIO_ACTIVE_HIGH>; */ -+ ti,sensor_delay = <350>; -+ ti,links = <2>; -+ ti,lanes = <4>; -+ ti,forwarding-mode = "round-robin"; -+ ti,cable-mode = "coax"; -+ -+ port@0 { -+ ti954_des1ep0: endpoint@0 { -+ ti9x3-addr = <0x0c>; -+ dvp-order = <0>; -+ remote-endpoint = <&ov106xx_in4>; -+ }; -+ ti954_des1ep1: endpoint@1 { -+ ti9x3-addr = <0x0d>; -+ dvp-order = <0>; -+ remote-endpoint = <&ov106xx_in5>; -+ }; -+ }; -+ port@1 { -+ ti954_csi2ep0: endpoint { ++ ti9x4_csi2ep0: endpoint { + csi-rate = <1450>; + remote-endpoint = <&csi2_41_ep>; + }; @@ -3644,11 +3488,8 @@ index 0000000..c19bc58 + vin0_max9286_des0ep0: endpoint@0 { + remote-endpoint = <&max9286_des0ep0>; + }; -+ vin0_ti964_des0ep0: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep0>; -+ }; -+ vin0_ti954_des0ep0: endpoint@2 { -+ remote-endpoint = <&ti954_des0ep0>; ++ vin0_ti9x4_des0ep0: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep0>; + }; + }; + }; @@ -3678,11 +3519,8 @@ index 0000000..c19bc58 + vin1_max9286_des0ep1: endpoint@0 { + remote-endpoint = <&max9286_des0ep1>; + }; -+ vin1_ti964_des0ep1: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep1>; -+ }; -+ vin1_ti954_des0ep1: endpoint@2 { -+ remote-endpoint = <&ti954_des0ep1>; ++ vin1_ti9x4_des0ep1: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep1>; + }; + }; + }; @@ -3712,8 +3550,8 @@ index 0000000..c19bc58 + vin2_max9286_des0ep2: endpoint@0 { + remote-endpoint = <&max9286_des0ep2>; + }; -+ vin2_ti964_des0ep2: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep2>; ++ vin2_ti9x4_des0ep2: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep2>; + }; + }; + }; @@ -3743,8 +3581,8 @@ index 0000000..c19bc58 + vin3_max9286_des0ep3: endpoint@0 { + remote-endpoint = <&max9286_des0ep3>; + }; -+ vin3_ti964_des0ep3: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep3>; ++ vin3_ti9x4_des0ep3: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep3>; + }; + }; + }; @@ -3774,11 +3612,8 @@ index 0000000..c19bc58 + vin4_max9286_des1ep0: endpoint@0 { + remote-endpoint = <&max9286_des1ep0>; + }; -+ vin4_ti964_des1ep0: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep0>; -+ }; -+ vin4_ti954_des1ep0: endpoint@2 { -+ remote-endpoint = <&ti954_des1ep0>; ++ vin4_ti9x4_des1ep0: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep0>; + }; + }; + }; @@ -3808,11 +3643,8 @@ index 0000000..c19bc58 + vin5_max9286_des1ep1: endpoint@0 { + remote-endpoint = <&max9286_des1ep1>; + }; -+ vin5_ti964_des1ep1: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep1>; -+ }; -+ vin5_ti954_des1ep1: endpoint@2 { -+ remote-endpoint = <&ti954_des1ep1>; ++ vin5_ti9x4_des1ep1: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep1>; + }; + }; + }; @@ -3842,8 +3674,8 @@ index 0000000..c19bc58 + vin6_max9286_des1ep2: endpoint@0 { + remote-endpoint = <&max9286_des1ep2>; + }; -+ vin6_ti964_des1ep2: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep2>; ++ vin6_ti9x4_des1ep2: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep2>; + }; + }; + }; @@ -3873,8 +3705,8 @@ index 0000000..c19bc58 + vin7_max9286_des1ep3: endpoint@0 { + remote-endpoint = <&max9286_des1ep3>; + }; -+ vin7_ti964_des1ep3: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep3>; ++ vin7_ti9x4_des1ep3: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep3>; + }; + }; + }; @@ -4536,10 +4368,10 @@ index 0000000..14b6f52 +}; diff --git a/arch/arm64/boot/dts/renesas/legacy/r8a7796-m3ulcb-kf-v0.dts b/arch/arm64/boot/dts/renesas/legacy/r8a7796-m3ulcb-kf-v0.dts new file mode 100644 -index 0000000..8e7de0f +index 0000000..b17a42e --- /dev/null +++ b/arch/arm64/boot/dts/renesas/legacy/r8a7796-m3ulcb-kf-v0.dts -@@ -0,0 +1,1214 @@ +@@ -0,0 +1,1171 @@ +/* + * Device Tree Source for the M3ULCB Kingfisher V0 board on r8a7796 + * @@ -5128,11 +4960,8 @@ index 0000000..8e7de0f + ov106xx_max9286_des0ep0: endpoint@0 { + remote-endpoint = <&max9286_des0ep0>; + }; -+ ov106xx_ti964_des0ep0: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep0>; -+ }; -+ ov106xx_ti954_des0ep0: endpoint@2 { -+ remote-endpoint = <&ti954_des0ep0>; ++ ov106xx_ti9x4_des0ep0: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep0>; + }; + }; + }; @@ -5152,11 +4981,8 @@ index 0000000..8e7de0f + ov106xx_max9286_des0ep1: endpoint@0 { + remote-endpoint = <&max9286_des0ep1>; + }; -+ ov106xx_ti964_des0ep1: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep1>; -+ }; -+ ov106xx_ti954_des0ep1: endpoint@2 { -+ remote-endpoint = <&ti954_des0ep1>; ++ ov106xx_ti9x4_des0ep1: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep1>; + }; + }; + }; @@ -5176,8 +5002,8 @@ index 0000000..8e7de0f + ov106xx_max9286_des0ep2: endpoint@0 { + remote-endpoint = <&max9286_des0ep2>; + }; -+ ov106xx_ti964_des0ep2: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep2>; ++ ov106xx_ti9x4_des0ep2: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep2>; + }; + }; + }; @@ -5197,15 +5023,15 @@ index 0000000..8e7de0f + ov106xx_max9286_des0ep3: endpoint@0 { + remote-endpoint = <&max9286_des0ep3>; + }; -+ ov106xx_ti964_des0ep3: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep3>; ++ ov106xx_ti9x4_des0ep3: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep3>; + }; + }; + }; + -+ /* DS90UB964 @ 0x3a */ -+ ti964-ti9x3@0 { -+ compatible = "ti,ti964-ti9x3"; ++ /* DS90UB9x4 @ 0x3a */ ++ ti9x4@0 { ++ compatible = "ti,ti9x4"; + reg = <0x3a>; + ti,sensor_delay = <350>; + ti,links = <4>; @@ -5214,60 +5040,29 @@ index 0000000..8e7de0f + ti,cable-mode = "coax"; + + port@0 { -+ ti964_des0ep0: endpoint@0 { ++ ti9x4_des0ep0: endpoint@0 { + ti9x3-addr = <0x0c>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in0>; + }; -+ ti964_des0ep1: endpoint@1 { ++ ti9x4_des0ep1: endpoint@1 { + ti9x3-addr = <0x0d>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in1>; + }; -+ ti964_des0ep2: endpoint@2 { ++ ti9x4_des0ep2: endpoint@2 { + ti9x3-addr = <0x0e>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in2>; + }; -+ ti964_des0ep3: endpoint@3 { ++ ti9x4_des0ep3: endpoint@3 { + ti9x3-addr = <0x0f>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in3>; + }; + }; + port@1 { -+ ti964_csi0ep0: endpoint { -+ csi-rate = <1450>; -+ remote-endpoint = <&csi2_40_ep>; -+ }; -+ }; -+ }; -+ -+ /* DS90UB954 @ 0x38 */ -+ ti954-ti9x3@0 { -+ compatible = "ti,ti954-ti9x3"; -+ reg = <0x38>; -+ /* gpios = <&video_a_ext1 10 GPIO_ACTIVE_HIGH>; */ -+ ti,sensor_delay = <350>; -+ ti,links = <2>; -+ ti,lanes = <4>; -+ ti,forwarding-mode = "round-robin"; -+ ti,cable-mode = "coax"; -+ -+ port@0 { -+ ti954_des0ep0: endpoint@0 { -+ ti9x3-addr = <0x0c>; -+ dvp-order = <0>; -+ remote-endpoint = <&ov106xx_in0>; -+ }; -+ ti954_des0ep1: endpoint@1 { -+ ti9x3-addr = <0x0d>; -+ dvp-order = <0>; -+ remote-endpoint = <&ov106xx_in1>; -+ }; -+ }; -+ port@1 { -+ ti954_csi0ep0: endpoint { ++ ti9x4_csi0ep0: endpoint { + csi-rate = <1450>; + remote-endpoint = <&csi2_40_ep>; + }; @@ -5499,11 +5294,8 @@ index 0000000..8e7de0f + vin0_max9286_des0ep0: endpoint@0 { + remote-endpoint = <&max9286_des0ep0>; + }; -+ vin0_ti964_des0ep0: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep0>; -+ }; -+ vin0_ti954_des0ep0: endpoint@2 { -+ remote-endpoint = <&ti954_des0ep0>; ++ vin0_ti9x4_des0ep0: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep0>; + }; + }; + }; @@ -5533,11 +5325,8 @@ index 0000000..8e7de0f + vin1_max9286_des0ep1: endpoint@0 { + remote-endpoint = <&max9286_des0ep1>; + }; -+ vin1_ti964_des0ep1: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep1>; -+ }; -+ vin1_ti954_des0ep1: endpoint@2 { -+ remote-endpoint = <&ti954_des0ep1>; ++ vin1_ti9x4_des0ep1: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep1>; + }; + }; + }; @@ -5567,8 +5356,8 @@ index 0000000..8e7de0f + vin2_max9286_des0ep2: endpoint@0 { + remote-endpoint = <&max9286_des0ep2>; + }; -+ vin2_ti964_des0ep2: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep2>; ++ vin2_ti9x4_des0ep2: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep2>; + }; + }; + }; @@ -5598,8 +5387,8 @@ index 0000000..8e7de0f + vin3_max9286_des0ep3: endpoint@0 { + remote-endpoint = <&max9286_des0ep3>; + }; -+ vin3_ti964_des0ep3: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep3>; ++ vin3_ti9x4_des0ep3: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep3>; + }; + }; + }; @@ -11023,10 +10812,10 @@ index 0000000..ce7a88e +}; diff --git a/arch/arm64/boot/dts/renesas/r8a7797-v3msk-kf.dts b/arch/arm64/boot/dts/renesas/r8a7797-v3msk-kf.dts new file mode 100644 -index 0000000..9158c84 +index 0000000..c61b613 --- /dev/null +++ b/arch/arm64/boot/dts/renesas/r8a7797-v3msk-kf.dts -@@ -0,0 +1,575 @@ +@@ -0,0 +1,533 @@ +/* + * Device Tree Source for the V3MSK Kingfisher board on r8a7797 + * @@ -11132,11 +10921,8 @@ index 0000000..9158c84 + ov106xx_max9286_des0ep0: endpoint@0 { + remote-endpoint = <&max9286_des0ep0>; + }; -+ ov106xx_ti964_des0ep0: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep0>; -+ }; -+ ov106xx_ti954_des0ep0: endpoint@2 { -+ remote-endpoint = <&ti954_des0ep0>; ++ ov106xx_ti9x4_des0ep0: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep0>; + }; + }; + }; @@ -11156,11 +10942,8 @@ index 0000000..9158c84 + ov106xx_max9286_des0ep1: endpoint@0 { + remote-endpoint = <&max9286_des0ep1>; + }; -+ ov106xx_ti964_des0ep1: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep1>; -+ }; -+ ov106xx_ti954_des0ep1: endpoint@2 { -+ remote-endpoint = <&ti954_des0ep1>; ++ ov106xx_ti9x4_des0ep1: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep1>; + }; + }; + }; @@ -11180,8 +10963,8 @@ index 0000000..9158c84 + ov106xx_max9286_des0ep2: endpoint@0 { + remote-endpoint = <&max9286_des0ep2>; + }; -+ ov106xx_ti964_des0ep2: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep2>; ++ ov106xx_ti9x4_des0ep2: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep2>; + }; + }; + }; @@ -11201,15 +10984,15 @@ index 0000000..9158c84 + ov106xx_max9286_des0ep3: endpoint@0 { + remote-endpoint = <&max9286_des0ep3>; + }; -+ ov106xx_ti964_des0ep3: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep3>; ++ ov106xx_ti9x4_des0ep3: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep3>; + }; + }; + }; + -+ /* DS90UB964 @ 0x3a */ -+ ti964-ti9x3@0 { -+ compatible = "ti,ti964-ti9x3"; ++ /* DS90UB9x4 @ 0x3a */ ++ ti9x4@0 { ++ compatible = "ti,ti9x4"; + reg = <0x3a>; + ti,links = <4>; + ti,lanes = <4>; @@ -11217,59 +11000,29 @@ index 0000000..9158c84 + ti,cable-mode = "coax"; + + port@0 { -+ ti964_des0ep0: endpoint@0 { ++ ti9x4_des0ep0: endpoint@0 { + ti9x3-addr = <0x0c>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in0>; + }; -+ ti964_des0ep1: endpoint@1 { ++ ti9x4_des0ep1: endpoint@1 { + ti9x3-addr = <0x0d>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in1>; + }; -+ ti964_des0ep2: endpoint@2 { ++ ti9x4_des0ep2: endpoint@2 { + ti9x3-addr = <0x0e>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in2>; + }; -+ ti964_des0ep3: endpoint@3 { ++ ti9x4_des0ep3: endpoint@3 { + ti9x3-addr = <0x0f>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in3>; + }; + }; + port@1 { -+ ti964_csi0ep0: endpoint { -+ csi-rate = <800>; -+ remote-endpoint = <&csi2_40_ep>; -+ }; -+ }; -+ }; -+ -+ /* DS90UB954 @ 0x38 */ -+ ti954-ti9x3@0 { -+ compatible = "ti,ti954-ti9x3"; -+ reg = <0x38>; -+ /* gpios = <&video_a_ext1 10 GPIO_ACTIVE_HIGH>; */ -+ ti,links = <2>; -+ ti,lanes = <4>; -+ ti,forwarding-mode = "round-robin"; -+ ti,cable-mode = "coax"; -+ -+ port@0 { -+ ti954_des0ep0: endpoint@0 { -+ ti9x3-addr = <0x0c>; -+ dvp-order = <0>; -+ remote-endpoint = <&ov106xx_in0>; -+ }; -+ ti954_des0ep1: endpoint@1 { -+ ti9x3-addr = <0x0d>; -+ dvp-order = <0>; -+ remote-endpoint = <&ov106xx_in1>; -+ }; -+ }; -+ port@1 { -+ ti954_csi0ep0: endpoint { ++ ti9x4_csi0ep0: endpoint { + csi-rate = <800>; + remote-endpoint = <&csi2_40_ep>; + }; @@ -11497,11 +11250,8 @@ index 0000000..9158c84 + vin0_max9286_des0ep0: endpoint@0 { + remote-endpoint = <&max9286_des0ep0>; + }; -+ vin0_ti964_des0ep0: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep0>; -+ }; -+ vin0_ti954_des0ep0: endpoint@2 { -+ remote-endpoint = <&ti954_des0ep0>; ++ vin0_ti9x4_des0ep0: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep0>; + }; + }; + }; @@ -11531,11 +11281,8 @@ index 0000000..9158c84 + vin1_max9286_des0ep1: endpoint@0 { + remote-endpoint = <&max9286_des0ep1>; + }; -+ vin1_ti964_des0ep1: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep1>; -+ }; -+ vin1_ti954_des0ep1: endpoint@2 { -+ remote-endpoint = <&ti954_des0ep1>; ++ vin1_ti9x4_des0ep1: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep1>; + }; + }; + }; @@ -11565,8 +11312,8 @@ index 0000000..9158c84 + vin2_max9286_des0ep2: endpoint@0 { + remote-endpoint = <&max9286_des0ep2>; + }; -+ vin2_ti964_des0ep2: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep2>; ++ vin2_ti9x4_des0ep2: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep2>; + }; + }; + }; @@ -11596,15 +11343,15 @@ index 0000000..9158c84 + vin3_max9286_des0ep3: endpoint@0 { + remote-endpoint = <&max9286_des0ep3>; + }; -+ vin3_ti964_des0ep3: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep3>; ++ vin3_ti9x4_des0ep3: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep3>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/renesas/r8a7797-v3msk-vbm.dts b/arch/arm64/boot/dts/renesas/r8a7797-v3msk-vbm.dts new file mode 100644 -index 0000000..1cb8e95 +index 0000000..d355adb --- /dev/null +++ b/arch/arm64/boot/dts/renesas/r8a7797-v3msk-vbm.dts @@ -0,0 +1,548 @@ @@ -11746,8 +11493,8 @@ index 0000000..1cb8e95 + ov106xx_max9286_des0ep0: endpoint@0 { + remote-endpoint = <&max9286_des0ep0>; + }; -+ ov106xx_ti964_des0ep0: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep0>; ++ ov106xx_ti9x4_des0ep0: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep0>; + }; + }; + }; @@ -11767,8 +11514,8 @@ index 0000000..1cb8e95 + ov106xx_max9286_des0ep1: endpoint@0 { + remote-endpoint = <&max9286_des0ep1>; + }; -+ ov106xx_ti964_des0ep1: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep1>; ++ ov106xx_ti9x4_des0ep1: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep1>; + }; + }; + }; @@ -11788,8 +11535,8 @@ index 0000000..1cb8e95 + ov106xx_max9286_des0ep2: endpoint@0 { + remote-endpoint = <&max9286_des0ep2>; + }; -+ ov106xx_ti964_des0ep2: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep2>; ++ ov106xx_ti9x4_des0ep2: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep2>; + }; + }; + }; @@ -11809,8 +11556,8 @@ index 0000000..1cb8e95 + ov106xx_max9286_des0ep3: endpoint@0 { + remote-endpoint = <&max9286_des0ep3>; + }; -+ ov106xx_ti964_des0ep3: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep3>; ++ ov106xx_ti9x4_des0ep3: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep3>; + }; + }; + }; @@ -11858,8 +11605,8 @@ index 0000000..1cb8e95 + }; + }; + -+ ti964-ti9x3@0 { -+ compatible = "ti,ti964-ti9x3"; ++ ti9x4@0 { ++ compatible = "ti,ti9x4"; + reg = <0x3a>; + ti,links = <4>; + ti,lanes = <4>; @@ -11871,29 +11618,29 @@ index 0000000..1cb8e95 + POC3-supply = <&pwr3>; + + port@0 { -+ ti964_des0ep0: endpoint@0 { ++ ti9x4_des0ep0: endpoint@0 { + ti9x3-addr = <0x0c>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in0>; + }; -+ ti964_des0ep1: endpoint@1 { ++ ti9x4_des0ep1: endpoint@1 { + ti9x3-addr = <0x0d>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in1>; + }; -+ ti964_des0ep2: endpoint@2 { ++ ti9x4_des0ep2: endpoint@2 { + ti9x3-addr = <0x0e>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in2>; + }; -+ ti964_des0ep3: endpoint@3 { ++ ti9x4_des0ep3: endpoint@3 { + ti9x3-addr = <0x0f>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in3>; + }; + }; + port@1 { -+ ti964_csi0ep0: endpoint { ++ ti9x4_csi0ep0: endpoint { + csi-rate = <700>; + remote-endpoint = <&csi2_40_ep>; + }; @@ -12057,8 +11804,8 @@ index 0000000..1cb8e95 + vin0_max9286_des0ep0: endpoint@0 { + remote-endpoint = <&max9286_des0ep0>; + }; -+ vin0_ti964_des0ep0: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep0>; ++ vin0_ti9x4_des0ep0: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep0>; + }; + }; + }; @@ -12088,8 +11835,8 @@ index 0000000..1cb8e95 + vin1_max9286_des0ep1: endpoint@0 { + remote-endpoint = <&max9286_des0ep1>; + }; -+ vin1_ti964_des0ep1: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep1>; ++ vin1_ti9x4_des0ep1: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep1>; + }; + }; + }; @@ -12119,8 +11866,8 @@ index 0000000..1cb8e95 + vin2_max9286_des0ep2: endpoint@0 { + remote-endpoint = <&max9286_des0ep2>; + }; -+ vin2_ti964_des0ep2: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep2>; ++ vin2_ti9x4_des0ep2: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep2>; + }; + }; + }; @@ -12150,8 +11897,8 @@ index 0000000..1cb8e95 + vin3_max9286_des0ep3: endpoint@0 { + remote-endpoint = <&max9286_des0ep3>; + }; -+ vin3_ti964_des0ep3: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep3>; ++ vin3_ti9x4_des0ep3: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep3>; + }; + }; + }; @@ -12779,16 +12526,15 @@ index 0000000..91d10c5 + non-removable; + status = "okay"; +}; -diff --git a/arch/arm64/boot/dts/renesas/r8a7798-condor.dts b/arch/arm64/boot/dts/renesas/r8a7798-condor.dts +diff --git a/arch/arm64/boot/dts/renesas/r8a7797-v3mzf.dts b/arch/arm64/boot/dts/renesas/r8a7797-v3mzf.dts new file mode 100644 -index 0000000..cdd9844 +index 0000000..7926d2e --- /dev/null -+++ b/arch/arm64/boot/dts/renesas/r8a7798-condor.dts -@@ -0,0 +1,963 @@ ++++ b/arch/arm64/boot/dts/renesas/r8a7797-v3mzf.dts +@@ -0,0 +1,424 @@ +/* -+ * Device Tree Source for the Condor board ++ * Device Tree Source for the V3MZF board + * -+ * Copyright (C) 2018 Renesas Electronics Corp. + * Copyright (C) 2018 Cogent Embedded, Inc. + * + * This file is licensed under the terms of the GNU General Public License @@ -12797,17 +12543,16 @@ index 0000000..cdd9844 + */ + +/dts-v1/; -+#include "r8a7798.dtsi" ++#include "r8a7797.dtsi" +#include + +/ { -+ model = "Renesas Condor board based on r8a7798"; -+ compatible = "renesas,condor", "renesas,r8a7798"; ++ model = "Renesas V3MZF board based on r8a7797"; ++ compatible = "renesas,v3mzf", "renesas,r8a7797"; + + aliases { + serial0 = &scif0; + ethernet0 = &avb; -+ ethernet1 = &gether; + }; + + chosen { @@ -12815,7 +12560,6 @@ index 0000000..cdd9844 + stdout-path = "serial0:115200n8"; + }; + -+ + memory@48000000 { + device_type = "memory"; + /* first 128MB is reserved for secure area. */ @@ -12837,16 +12581,9 @@ index 0000000..cdd9844 + linux,cma { + compatible = "shared-dma-pool"; + reusable; -+ reg = <0x00000000 0x6f000000 0x0 0x10000000>; ++ reg = <0x00000000 0x6f000000 0x0 0x11000000>; + linux,cma-default; + }; -+ -+ /* device specific region for contiguous allocations */ -+ linux,multimedia { -+ compatible = "shared-dma-pool"; -+ reusable; -+ reg = <0x00000000 0x7f000000 0x0 0x01000000>; -+ }; + }; + + mmngr { @@ -12891,15 +12628,15 @@ index 0000000..cdd9844 + height-mm = <158>; + + panel-timing { -+ clock-frequency = <138000000>; -+ hactive = <1920>; -+ vactive = <1080>; -+ hsync-len = <32>; -+ hfront-porch = <20>; -+ hback-porch = <160>; -+ vfront-porch = <3>; -+ vback-porch = <31>; -+ vsync-len = <5>; ++ clock-frequency = <65000000>; ++ hactive = <1280>; ++ vactive = <800>; ++ hsync-len = <40>; ++ hfront-porch = <80>; ++ hback-porch = <40>; ++ vfront-porch = <14>; ++ vback-porch = <14>; ++ vsync-len = <4>; + }; + + port { @@ -12909,17 +12646,6 @@ index 0000000..cdd9844 + }; + }; + -+ hdmi-out { -+ compatible = "hdmi-connector"; -+ type = "a"; -+ -+ port { -+ hdmi_con: endpoint { -+ remote-endpoint = <&adv7511_out>; -+ }; -+ }; -+ }; -+ + dclkin_p0: clock-out0 { + compatible = "fixed-clock"; + #clock-cells = <0>; @@ -12931,27 +12657,478 @@ index 0000000..cdd9844 + #clock-cells = <0>; + clock-frequency = <66666666>; + }; ++}; + -+ vcc_3v3: regulator0 { -+ compatible = "regulator-fixed"; -+ regulator-name = "fixed-VCC3V3"; -+ regulator-min-microvolt = <3300000>; -+ regulator-max-microvolt = <3300000>; -+ regulator-boot-on; -+ regulator-always-on; -+ }; ++&avb { ++ pinctrl-0 = <&avb_pins>; ++ pinctrl-names = "default"; ++ renesas,no-ether-link; ++ phy-handle = <&phy0>; ++ status = "okay"; ++ phy-int-gpio = <&gpio1 17 GPIO_ACTIVE_LOW>; + -+ vcc_vddq_vin0: regulator1 { -+ compatible = "regulator-fixed"; -+ regulator-name = "VCC-VDDQ-VIN0"; -+ regulator-min-microvolt = <1800000>; -+ regulator-max-microvolt = <1800000>; -+ regulator-boot-on; -+ regulator-always-on; ++ phy0: ethernet-phy@0 { ++ rxc-skew-ps = <1500>; ++ rxdv-skew-ps = <420>; /* default */ ++ rxd0-skew-ps = <420>; /* default */ ++ rxd1-skew-ps = <420>; /* default */ ++ rxd2-skew-ps = <420>; /* default */ ++ rxd3-skew-ps = <420>; /* default */ ++ txc-skew-ps = <900>; /* default */ ++ txen-skew-ps = <420>; /* default */ ++ txd0-skew-ps = <420>; /* default */ ++ txd1-skew-ps = <420>; /* default */ ++ txd2-skew-ps = <420>; /* default */ ++ txd3-skew-ps = <420>; /* default */ ++ reg = <0>; ++ interrupt-parent = <&gpio1>; ++ interrupts = <17 IRQ_TYPE_LEVEL_LOW>; ++ max-speed = <1000>; + }; +}; + -+&du { ++&canfd { ++ pinctrl-0 = <&canfd0_pins &canfd1_pins>; ++ pinctrl-names = "default"; ++ status = "okay"; ++ ++ channel0 { ++ status = "okay"; ++ }; ++ ++ channel1 { ++ status = "okay"; ++ }; ++}; ++ ++&csi2_40 { ++ status = "okay"; ++ ++ virtual,channel { ++ csi2_vc0 { ++ data,type = "raw8"; ++ receive,vc = <0>; ++ }; ++ }; ++ ++ port { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ csi2_40_ep: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ csi-rate = <300>; ++ }; ++ }; ++}; ++ ++&du { ++ status = "okay"; ++ ++ ports { ++ port@0 { ++ endpoint { ++ remote-endpoint = <&lvds_in>; ++ }; ++ }; ++ }; ++}; ++ ++&extal_clk { ++ clock-frequency = <16666666>; ++}; ++ ++&extalr_clk { ++ clock-frequency = <32768>; ++}; ++ ++&gpio1 { ++ pdb_ser_enable { ++ gpio-hog; ++ gpios = <26 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "PDB_SER_Enable"; ++ }; ++ ++ lvds_sw_sel { ++ gpio-hog; ++ gpios = <27 GPIO_ACTIVE_HIGH>; ++ output-low; ++ line-name = "LVDS_SW_SEL"; ++ }; ++}; ++ ++&gpio2 { ++ can0_inh_v3m { ++ gpio-hog; ++ gpios = <14 GPIO_ACTIVE_HIGH>; ++ output-low; ++ line-name = "CAN0_INH_V3M"; ++ }; ++ ++ can1_inh_v3m { ++ gpio-hog; ++ gpios = <15 GPIO_ACTIVE_HIGH>; ++ output-low; ++ line-name = "CAN1_INH_V3M"; ++ }; ++}; ++ ++&gpio3 { ++ pdb_des_enable { ++ gpio-hog; ++ gpios = <0 GPIO_ACTIVE_HIGH>; ++ output-high; ++ line-name = "PDB_DES_Enable"; ++ }; ++}; ++ ++&i2c0 { ++ pinctrl-0 = <&i2c0_pins>; ++ pinctrl-names = "default"; ++ ++ status = "okay"; ++ clock-frequency = <400000>; ++}; ++ ++&i2c3 { ++ pinctrl-0 = <&i2c3_pins>; ++ pinctrl-names = "default"; ++ ++ status = "okay"; ++ clock-frequency = <400000>; ++ ++ ov106xx@0 { ++ compatible = "ovti,ov106xx"; ++ reg = <0x60>; ++ ++ port@0 { ++ ov106xx_in0: endpoint { ++ clock-lanes = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&vin0ep0>; ++ }; ++ }; ++ port@1 { ++ ov106xx_ti9x4_des0ep0: endpoint@0 { ++ remote-endpoint = <&ti9x4_des0ep0>; ++ }; ++ }; ++ }; ++ ++ ti9x4@30 { ++ compatible = "ti,ti9x4"; ++ reg = <0x30>; ++ ti,links = <1>; ++ ti,lanes = <4>; ++ ti,forwarding-mode = "round-robin"; ++ ti,dvp_bus = <0>; ++ ti,ser_id = <0x30>; ++ ++ port@0 { ++ ti9x4_des0ep0: endpoint@0 { ++ ti9x3-addr = <0x0c>; ++ dvp-order = <0>; ++ remote-endpoint = <&ov106xx_in0>; ++ }; ++ }; ++ port@1 { ++ ti9x4_csi0ep0: endpoint { ++ csi-rate = <800>; ++ remote-endpoint = <&csi2_40_ep>; ++ }; ++ }; ++ }; ++}; ++ ++&msiof2 { ++ pinctrl-0 = <&msiof2_pins>; ++ pinctrl-names = "default"; ++ cs-gpios = <&gpio2 4 0>; ++ ++ status = "okay"; ++ spidev@0 { ++ compatible = "renesas,sh-msiof"; ++ reg = <0>; ++ spi-max-frequency = <66666666>; ++ }; ++}; ++ ++&msiof3 { ++ pinctrl-0 = <&msiof3_pins>; ++ pinctrl-names = "default"; ++ ++ status = "okay"; ++ slave; ++}; ++ ++&pfc { ++ pinctrl-0 = <&scif_clk_pins>; ++ pinctrl-names = "default"; ++ ++ avb_pins: avb { ++ groups = "avb0_mdc"; ++ function = "avb0"; ++ }; ++ ++ canfd0_pins: canfd0 { ++ groups = "canfd0_data_a"; ++ function = "canfd0"; ++ }; ++ ++ canfd1_pins: canfd1 { ++ groups = "canfd1_data"; ++ function = "canfd1"; ++ }; ++ ++ i2c0_pins: i2c0 { ++ groups = "i2c0"; ++ function = "i2c0"; ++ }; ++ ++ i2c3_pins: i2c3 { ++ groups = "i2c3"; ++ function = "i2c3"; ++ }; ++ ++ msiof2_pins: msiof2 { ++ groups = "msiof2_clk", "msiof2_txd", "msiof2_rxd"; ++ function = "msiof2"; ++ }; ++ ++ msiof3_pins: msiof3 { ++ groups = "msiof3_clk", "msiof3_txd", "msiof3_rxd", "msiof3_sync"; ++ function = "msiof3"; ++ }; ++ ++ scif0_pins: scif0 { ++ groups = "scif0_data"; ++ function = "scif0"; ++ }; ++ ++ scif_clk_pins: scif_clk { ++ groups = "scif_clk_b"; ++ function = "scif_clk"; ++ }; ++}; ++ ++&scif0 { ++ pinctrl-0 = <&scif0_pins>; ++ pinctrl-names = "default"; ++ ++ status = "okay"; ++}; ++ ++&scif_clk { ++ clock-frequency = <14745600>; ++ status = "okay"; ++}; ++ ++&vin0 { ++ status = "okay"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ vin0ep0: endpoint { ++ csi,select = "csi40"; ++ virtual,channel = <0>; ++ data-lanes = <1 2 3 4>; ++ remote-endpoint = <&ov106xx_in0>; ++ }; ++ }; ++ port@1 { ++ csi0ep0: endpoint { ++ remote-endpoint = <&csi2_40_ep>; ++ }; ++ }; ++ port@2 { ++ vin0_ti9x4_des0ep0: endpoint@0 { ++ remote-endpoint = <&ti9x4_des0ep0>; ++ }; ++ }; ++ }; ++}; ++ ++&wdt0 { ++ status = "okay"; ++}; +diff --git a/arch/arm64/boot/dts/renesas/r8a7798-condor.dts b/arch/arm64/boot/dts/renesas/r8a7798-condor.dts +new file mode 100644 +index 0000000..cdd9844 +--- /dev/null ++++ b/arch/arm64/boot/dts/renesas/r8a7798-condor.dts +@@ -0,0 +1,963 @@ ++/* ++ * Device Tree Source for the Condor board ++ * ++ * Copyright (C) 2018 Renesas Electronics Corp. ++ * Copyright (C) 2018 Cogent Embedded, Inc. ++ * ++ * This file is licensed under the terms of the GNU General Public License ++ * version 2. This program is licensed "as is" without any warranty of any ++ * kind, whether express or implied. ++ */ ++ ++/dts-v1/; ++#include "r8a7798.dtsi" ++#include ++ ++/ { ++ model = "Renesas Condor board based on r8a7798"; ++ compatible = "renesas,condor", "renesas,r8a7798"; ++ ++ aliases { ++ serial0 = &scif0; ++ ethernet0 = &avb; ++ ethernet1 = &gether; ++ }; ++ ++ chosen { ++ bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp"; ++ stdout-path = "serial0:115200n8"; ++ }; ++ ++ ++ memory@48000000 { ++ device_type = "memory"; ++ /* first 128MB is reserved for secure area. */ ++ reg = <0x0 0x48000000 0x0 0x38000000>; ++ }; ++ ++ reserved-memory { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ranges; ++ ++ /* device specific region for Lossy Decompression */ ++ lossy_decompress: linux,lossy_decompress { ++ no-map; ++ reg = <0x00000000 0x6c000000 0x0 0x03000000>; ++ }; ++ ++ /* global autoconfigured region for contiguous allocations */ ++ linux,cma { ++ compatible = "shared-dma-pool"; ++ reusable; ++ reg = <0x00000000 0x6f000000 0x0 0x10000000>; ++ linux,cma-default; ++ }; ++ ++ /* device specific region for contiguous allocations */ ++ linux,multimedia { ++ compatible = "shared-dma-pool"; ++ reusable; ++ reg = <0x00000000 0x7f000000 0x0 0x01000000>; ++ }; ++ }; ++ ++ mmngr { ++ compatible = "renesas,mmngr"; ++ memory-region = <&lossy_decompress>; ++ }; ++ ++ mmngrbuf { ++ compatible = "renesas,mmngrbuf"; ++ }; ++ ++ vspm_if { ++ compatible = "renesas,vspm_if"; ++ }; ++ ++ lvds-encoder { ++ compatible = "thine,thc63lvdm83d"; ++ ++ ports { ++ #address-cells = <1>; ++ #size-cells = <0>; ++ ++ port@0 { ++ reg = <0>; ++ lvds_enc_in: endpoint { ++ remote-endpoint = <&du_out_lvds0>; ++ }; ++ }; ++ port@1 { ++ reg = <1>; ++ lvds_enc_out: endpoint { ++ remote-endpoint = <&lvds_in>; ++ }; ++ }; ++ }; ++ }; ++ ++ lvds { ++ compatible = "lvds-connector"; ++ ++ width-mm = <210>; ++ height-mm = <158>; ++ ++ panel-timing { ++ clock-frequency = <138000000>; ++ hactive = <1920>; ++ vactive = <1080>; ++ hsync-len = <32>; ++ hfront-porch = <20>; ++ hback-porch = <160>; ++ vfront-porch = <3>; ++ vback-porch = <31>; ++ vsync-len = <5>; ++ }; ++ ++ port { ++ lvds_in: endpoint { ++ remote-endpoint = <&lvds_enc_out>; ++ }; ++ }; ++ }; ++ ++ hdmi-out { ++ compatible = "hdmi-connector"; ++ type = "a"; ++ ++ port { ++ hdmi_con: endpoint { ++ remote-endpoint = <&adv7511_out>; ++ }; ++ }; ++ }; ++ ++ dclkin_p0: clock-out0 { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <148500000>; ++ }; ++ ++ msiof_ref_clk: msiof-ref-clock { ++ compatible = "fixed-clock"; ++ #clock-cells = <0>; ++ clock-frequency = <66666666>; ++ }; ++ ++ vcc_3v3: regulator0 { ++ compatible = "regulator-fixed"; ++ regulator-name = "fixed-VCC3V3"; ++ regulator-min-microvolt = <3300000>; ++ regulator-max-microvolt = <3300000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++ ++ vcc_vddq_vin0: regulator1 { ++ compatible = "regulator-fixed"; ++ regulator-name = "VCC-VDDQ-VIN0"; ++ regulator-min-microvolt = <1800000>; ++ regulator-max-microvolt = <1800000>; ++ regulator-boot-on; ++ regulator-always-on; ++ }; ++}; ++ ++&du { + status = "okay"; + + ports { @@ -13750,10 +13927,10 @@ index 0000000..cdd9844 +}; diff --git a/arch/arm64/boot/dts/renesas/ulcb-kf-cn11.dtsi b/arch/arm64/boot/dts/renesas/ulcb-kf-cn11.dtsi new file mode 100644 -index 0000000..b469ca6 +index 0000000..095a503 --- /dev/null +++ b/arch/arm64/boot/dts/renesas/ulcb-kf-cn11.dtsi -@@ -0,0 +1,545 @@ +@@ -0,0 +1,498 @@ +/* + * Device Tree Source for the H3ULCB Kingfisher board: + * this adding conflicting resource on VIN4/VIN5/VIN6/VIN7 for CN11 @@ -13827,11 +14004,8 @@ index 0000000..b469ca6 + ov106xx_max9286_des1ep0: endpoint@0 { + remote-endpoint = <&max9286_des1ep0>; + }; -+ ov106xx_ti964_des1ep0: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep0>; -+ }; -+ ov106xx_ti954_des1ep0: endpoint@2 { -+ remote-endpoint = <&ti954_des1ep0>; ++ ov106xx_ti9x4_des1ep0: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep0>; + }; + }; + }; @@ -13851,11 +14025,8 @@ index 0000000..b469ca6 + ov106xx_max9286_des1ep1: endpoint@0 { + remote-endpoint = <&max9286_des1ep1>; + }; -+ ov106xx_ti964_des1ep1: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep1>; -+ }; -+ ov106xx_ti954_des1ep1: endpoint@2 { -+ remote-endpoint = <&ti954_des1ep1>; ++ ov106xx_ti9x4_des1ep1: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep1>; + }; + }; + }; @@ -13874,8 +14045,8 @@ index 0000000..b469ca6 + ov106xx_max9286_des1ep2: endpoint@0 { + remote-endpoint = <&max9286_des1ep2>; + }; -+ ov106xx_ti964_des1ep2: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep2>; ++ ov106xx_ti9x4_des1ep2: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep2>; + }; + }; + }; @@ -13894,15 +14065,15 @@ index 0000000..b469ca6 + ov106xx_max9286_des1ep3: endpoint@0 { + remote-endpoint = <&max9286_des1ep3>; + }; -+ ov106xx_ti964_des1ep3: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep3>; ++ ov106xx_ti9x4_des1ep3: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep3>; + }; + }; + }; + -+ /* DS90UB964 @ 0x3a */ -+ ti964-ti9x3@1 { -+ compatible = "ti,ti964-ti9x3"; ++ /* DS90UB9x4 @ 0x3a */ ++ ti9x4@1 { ++ compatible = "ti,ti9x4"; + reg = <0x3a>; + ti,sensor_delay = <350>; + ti,links = <4>; @@ -13915,64 +14086,29 @@ index 0000000..b469ca6 + POC3-supply = <&pwr3B>; + + port@0 { -+ ti964_des1ep0: endpoint@0 { ++ ti9x4_des1ep0: endpoint@0 { + ti9x3-addr = <0x0c>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in4>; + }; -+ ti964_des1ep1: endpoint@1 { ++ ti9x4_des1ep1: endpoint@1 { + ti9x3-addr = <0x0d>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in5>; + }; -+ ti964_des1ep2: endpoint@2 { ++ ti9x4_des1ep2: endpoint@2 { + ti9x3-addr = <0x0e>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in6>; + }; -+ ti964_des1ep3: endpoint@3 { ++ ti9x4_des1ep3: endpoint@3 { + ti9x3-addr = <0x0f>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in7>; + }; + }; + port@1 { -+ ti964_csi2ep0: endpoint { -+ csi-rate = <1450>; -+ remote-endpoint = <&csi2_41_ep>; -+ }; -+ }; -+ }; -+ -+ /* DS90UB954 @ 0x38 */ -+ ti954-ti9x3@1 { -+ compatible = "ti,ti954-ti9x3"; -+ reg = <0x38>; -+ /* gpios = <&video_b_ext1 10 GPIO_ACTIVE_HIGH>; */ -+ ti,sensor_delay = <350>; -+ ti,links = <2>; -+ ti,lanes = <4>; -+ ti,forwarding-mode = "round-robin"; -+ ti,cable-mode = "coax"; -+ POC0-supply = <&pwr0B>; -+ POC1-supply = <&pwr1B>; -+ POC2-supply = <&pwr2B>; -+ POC3-supply = <&pwr3B>; -+ -+ port@0 { -+ ti954_des1ep0: endpoint@0 { -+ ti9x3-addr = <0x0c>; -+ dvp-order = <0>; -+ remote-endpoint = <&ov106xx_in4>; -+ }; -+ ti954_des1ep1: endpoint@1 { -+ ti9x3-addr = <0x0d>; -+ dvp-order = <0>; -+ remote-endpoint = <&ov106xx_in5>; -+ }; -+ }; -+ port@1 { -+ ti954_csi2ep0: endpoint { ++ ti9x4_csi2ep0: endpoint { + csi-rate = <1450>; + remote-endpoint = <&csi2_41_ep>; + }; @@ -14162,11 +14298,8 @@ index 0000000..b469ca6 + vin4_max9286_des1ep0: endpoint@0 { + remote-endpoint = <&max9286_des1ep0>; + }; -+ vin4_ti964_des1ep0: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep0>; -+ }; -+ vin4_ti954_des1ep0: endpoint@2 { -+ remote-endpoint = <&ti954_des1ep0>; ++ vin4_ti9x4_des1ep0: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep0>; + }; + }; + }; @@ -14194,11 +14327,8 @@ index 0000000..b469ca6 + vin5_max9286_des1ep1: endpoint@0 { + remote-endpoint = <&max9286_des1ep1>; + }; -+ vin5_ti964_des1ep1: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep1>; -+ }; -+ vin5_ti954_des1ep1: endpoint@2 { -+ remote-endpoint = <&ti954_des1ep1>; ++ vin5_ti9x4_des1ep1: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep1>; + }; + }; + }; @@ -14228,8 +14358,8 @@ index 0000000..b469ca6 + vin6_max9286_des1ep2: endpoint@0 { + remote-endpoint = <&max9286_des1ep2>; + }; -+ vin6_ti964_des1ep2: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep2>; ++ vin6_ti9x4_des1ep2: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep2>; + }; + }; + }; @@ -14259,8 +14389,8 @@ index 0000000..b469ca6 + vin7_max9286_des1ep3: endpoint@0 { + remote-endpoint = <&max9286_des1ep3>; + }; -+ vin7_ti964_des1ep3: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep3>; ++ vin7_ti9x4_des1ep3: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep3>; + }; + }; + }; @@ -14389,10 +14519,10 @@ index 0000000..b854216 +}; diff --git a/arch/arm64/boot/dts/renesas/ulcb-kf.dtsi b/arch/arm64/boot/dts/renesas/ulcb-kf.dtsi new file mode 100644 -index 0000000..56194b4 +index 0000000..a33a2a0 --- /dev/null +++ b/arch/arm64/boot/dts/renesas/ulcb-kf.dtsi -@@ -0,0 +1,1538 @@ +@@ -0,0 +1,1492 @@ +/* + * Device Tree Source for the ULCB Kingfisher board + * @@ -15208,11 +15338,8 @@ index 0000000..56194b4 + ov106xx_max9286_des0ep0: endpoint@0 { + remote-endpoint = <&max9286_des0ep0>; + }; -+ ov106xx_ti964_des0ep0: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep0>; -+ }; -+ ov106xx_ti954_des0ep0: endpoint@2 { -+ remote-endpoint = <&ti954_des0ep0>; ++ ov106xx_ti9x4_des0ep0: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep0>; + }; + }; + }; @@ -15232,11 +15359,8 @@ index 0000000..56194b4 + ov106xx_max9286_des0ep1: endpoint@0 { + remote-endpoint = <&max9286_des0ep1>; + }; -+ ov106xx_ti964_des0ep1: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep1>; -+ }; -+ ov106xx_ti954_des0ep1: endpoint@2 { -+ remote-endpoint = <&ti954_des0ep1>; ++ ov106xx_ti9x4_des0ep1: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep1>; + }; + }; + }; @@ -15256,8 +15380,8 @@ index 0000000..56194b4 + ov106xx_max9286_des0ep2: endpoint@0 { + remote-endpoint = <&max9286_des0ep2>; + }; -+ ov106xx_ti964_des0ep2: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep2>; ++ ov106xx_ti9x4_des0ep2: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep2>; + }; + }; + }; @@ -15277,15 +15401,15 @@ index 0000000..56194b4 + ov106xx_max9286_des0ep3: endpoint@0 { + remote-endpoint = <&max9286_des0ep3>; + }; -+ ov106xx_ti964_des0ep3: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep3>; ++ ov106xx_ti9x4_des0ep3: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep3>; + }; + }; + }; + -+ /* DS90UB964 @ 0x3a */ -+ ti964-ti9x3@0 { -+ compatible = "ti,ti964-ti9x3"; ++ /* DS90UB9x4 @ 0x3a */ ++ ti9x4@0 { ++ compatible = "ti,ti9x4"; + reg = <0x3a>; + ti,links = <4>; + ti,lanes = <4>; @@ -15297,63 +15421,29 @@ index 0000000..56194b4 + POC3-supply = <&pwr3A>; + + port@0 { -+ ti964_des0ep0: endpoint@0 { ++ ti9x4_des0ep0: endpoint@0 { + ti9x3-addr = <0x0c>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in0>; + }; -+ ti964_des0ep1: endpoint@1 { ++ ti9x4_des0ep1: endpoint@1 { + ti9x3-addr = <0x0d>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in1>; + }; -+ ti964_des0ep2: endpoint@2 { ++ ti9x4_des0ep2: endpoint@2 { + ti9x3-addr = <0x0e>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in2>; + }; -+ ti964_des0ep3: endpoint@3 { ++ ti9x4_des0ep3: endpoint@3 { + ti9x3-addr = <0x0f>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in3>; + }; + }; + port@1 { -+ ti964_csi0ep0: endpoint { -+ csi-rate = <1450>; -+ remote-endpoint = <&csi2_40_ep>; -+ }; -+ }; -+ }; -+ -+ /* DS90UB954 @ 0x38 */ -+ ti954-ti9x3@0 { -+ compatible = "ti,ti954-ti9x3"; -+ reg = <0x38>; -+ /* gpios = <&video_a_ext1 10 GPIO_ACTIVE_HIGH>; */ -+ ti,links = <2>; -+ ti,lanes = <4>; -+ ti,forwarding-mode = "round-robin"; -+ ti,cable-mode = "coax"; -+ POC0-supply = <&pwr0A>; -+ POC1-supply = <&pwr1A>; -+ POC2-supply = <&pwr2A>; -+ POC3-supply = <&pwr3A>; -+ -+ port@0 { -+ ti954_des0ep0: endpoint@0 { -+ ti9x3-addr = <0x0c>; -+ dvp-order = <0>; -+ remote-endpoint = <&ov106xx_in0>; -+ }; -+ ti954_des0ep1: endpoint@1 { -+ ti9x3-addr = <0x0d>; -+ dvp-order = <0>; -+ remote-endpoint = <&ov106xx_in1>; -+ }; -+ }; -+ port@1 { -+ ti954_csi0ep0: endpoint { ++ ti9x4_csi0ep0: endpoint { + csi-rate = <1450>; + remote-endpoint = <&csi2_40_ep>; + }; @@ -15603,11 +15693,8 @@ index 0000000..56194b4 + vin0_max9286_des0ep0: endpoint@0 { + remote-endpoint = <&max9286_des0ep0>; + }; -+ vin0_ti964_des0ep0: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep0>; -+ }; -+ vin0_ti954_des0ep0: endpoint@2 { -+ remote-endpoint = <&ti954_des0ep0>; ++ vin0_ti9x4_des0ep0: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep0>; + }; + }; + }; @@ -15637,11 +15724,8 @@ index 0000000..56194b4 + vin1_max9286_des0ep1: endpoint@0 { + remote-endpoint = <&max9286_des0ep1>; + }; -+ vin1_ti964_des0ep1: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep1>; -+ }; -+ vin1_ti954_des0ep1: endpoint@2 { -+ remote-endpoint = <&ti954_des0ep1>; ++ vin1_ti9x4_des0ep1: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep1>; + }; + }; + }; @@ -15671,8 +15755,8 @@ index 0000000..56194b4 + vin2_max9286_des0ep2: endpoint@0 { + remote-endpoint = <&max9286_des0ep2>; + }; -+ vin2_ti964_des0ep2: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep2>; ++ vin2_ti9x4_des0ep2: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep2>; + }; + }; + }; @@ -15702,8 +15786,8 @@ index 0000000..56194b4 + vin3_max9286_des0ep3: endpoint@0 { + remote-endpoint = <&max9286_des0ep3>; + }; -+ vin3_ti964_des0ep3: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep3>; ++ vin3_ti9x4_des0ep3: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep3>; + }; + }; + }; @@ -15933,10 +16017,10 @@ index 0000000..56194b4 + diff --git a/arch/arm64/boot/dts/renesas/ulcb-vb-cn12.dtsi b/arch/arm64/boot/dts/renesas/ulcb-vb-cn12.dtsi new file mode 100644 -index 0000000..df27324 +index 0000000..778a477 --- /dev/null +++ b/arch/arm64/boot/dts/renesas/ulcb-vb-cn12.dtsi -@@ -0,0 +1,542 @@ +@@ -0,0 +1,495 @@ +/* + * Device Tree Source for the H3ULCB Videobox board: + * this adding conflicting resource on VIN4/VIN5/VIN6/VIN7 for CN12 @@ -16009,11 +16093,8 @@ index 0000000..df27324 + ov106xx_max9286_des2ep0: endpoint@0 { + remote-endpoint = <&max9286_des2ep0>; + }; -+ ov106xx_ti964_des2ep0: endpoint@1 { -+ remote-endpoint = <&ti964_des2ep0>; -+ }; -+ ov106xx_ti954_des2ep0: endpoint@2 { -+ remote-endpoint = <&ti954_des2ep0>; ++ ov106xx_ti9x4_des2ep0: endpoint@1 { ++ remote-endpoint = <&ti9x4_des2ep0>; + }; + }; + }; @@ -16033,11 +16114,8 @@ index 0000000..df27324 + ov106xx_max9286_des2ep1: endpoint@0 { + remote-endpoint = <&max9286_des2ep1>; + }; -+ ov106xx_ti964_des2ep1: endpoint@1 { -+ remote-endpoint = <&ti964_des2ep1>; -+ }; -+ ov106xx_ti954_des2ep1: endpoint@2 { -+ remote-endpoint = <&ti954_des2ep1>; ++ ov106xx_ti9x4_des2ep1: endpoint@1 { ++ remote-endpoint = <&ti9x4_des2ep1>; + }; + }; + }; @@ -16057,8 +16135,8 @@ index 0000000..df27324 + ov106xx_max9286_des2ep2: endpoint@0 { + remote-endpoint = <&max9286_des2ep2>; + }; -+ ov106xx_ti964_des2ep2: endpoint@1 { -+ remote-endpoint = <&ti964_des2ep2>; ++ ov106xx_ti9x4_des2ep2: endpoint@1 { ++ remote-endpoint = <&ti9x4_des2ep2>; + }; + }; + }; @@ -16078,15 +16156,15 @@ index 0000000..df27324 + ov106xx_max9286_des2ep3: endpoint@0 { + remote-endpoint = <&max9286_des2ep3>; + }; -+ ov106xx_ti964_des2ep3: endpoint@1 { -+ remote-endpoint = <&ti964_des2ep3>; ++ ov106xx_ti9x4_des2ep3: endpoint@1 { ++ remote-endpoint = <&ti9x4_des2ep3>; + }; + }; + }; + -+ /* DS90UB964 @ 0x3a */ -+ ti964-ti9x3@2 { -+ compatible = "ti,ti964-ti9x3"; ++ /* DS90UB9x4 @ 0x3a */ ++ ti9x4@2 { ++ compatible = "ti,ti9x4"; + reg = <0x3a>; + ti,sensor_delay = <350>; + ti,links = <4>; @@ -16099,64 +16177,29 @@ index 0000000..df27324 + POC3-supply = <&pwr3C>; + + port@0 { -+ ti964_des2ep0: endpoint@0 { ++ ti9x4_des2ep0: endpoint@0 { + ti9x3-addr = <0x0c>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in8>; + }; -+ ti964_des2ep1: endpoint@1 { ++ ti9x4_des2ep1: endpoint@1 { + ti9x3-addr = <0x0d>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in9>; + }; -+ ti964_des2ep2: endpoint@2 { ++ ti9x4_des2ep2: endpoint@2 { + ti9x3-addr = <0x0e>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in10>; + }; -+ ti964_des2ep3: endpoint@3 { ++ ti9x4_des2ep3: endpoint@3 { + ti9x3-addr = <0x0f>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in11>; + }; + }; + port@1 { -+ ti964_csi1ep0: endpoint { -+ csi-rate = <1450>; -+ remote-endpoint = <&csi2_20_ep>; -+ }; -+ }; -+ }; -+ -+ /* DS90UB954 @ 0x38 */ -+ ti954-ti9x3@2 { -+ compatible = "ti,ti954-ti9x3"; -+ reg = <0x38>; -+ /* gpios = <&gpio_exp_c_5c 10 GPIO_ACTIVE_HIGH>; */ -+ ti,sensor_delay = <350>; -+ ti,links = <2>; -+ ti,lanes = <2>; -+ ti,forwarding-mode = "round-robin"; -+ ti,cable-mode = "coax"; -+ POC0-supply = <&pwr0C>; -+ POC1-supply = <&pwr1C>; -+ POC2-supply = <&pwr2C>; -+ POC3-supply = <&pwr3C>; -+ -+ port@0 { -+ ti954_des2ep0: endpoint@0 { -+ ti9x3-addr = <0x0c>; -+ dvp-order = <0>; -+ remote-endpoint = <&ov106xx_in8>; -+ }; -+ ti954_des2ep1: endpoint@1 { -+ ti9x3-addr = <0x0d>; -+ dvp-order = <0>; -+ remote-endpoint = <&ov106xx_in9>; -+ }; -+ }; -+ port@1 { -+ ti954_csi1ep0: endpoint { ++ ti9x4_csi1ep0: endpoint { + csi-rate = <1450>; + remote-endpoint = <&csi2_20_ep>; + }; @@ -16346,11 +16389,8 @@ index 0000000..df27324 + vin4_max9286_des2ep0: endpoint@0 { + remote-endpoint = <&max9286_des2ep0>; + }; -+ vin4_ti964_des2ep0: endpoint@1 { -+ remote-endpoint = <&ti964_des2ep0>; -+ }; -+ vin4_ti954_des2ep0: endpoint@2 { -+ remote-endpoint = <&ti954_des2ep0>; ++ vin4_ti9x4_des2ep0: endpoint@1 { ++ remote-endpoint = <&ti9x4_des2ep0>; + }; + }; + }; @@ -16378,11 +16418,8 @@ index 0000000..df27324 + vin5_max9286_des2ep1: endpoint@0 { + remote-endpoint = <&max9286_des2ep1>; + }; -+ vin5_ti964_des2ep1: endpoint@1 { -+ remote-endpoint = <&ti964_des2ep1>; -+ }; -+ vin5_ti954_des2ep1: endpoint@2 { -+ remote-endpoint = <&ti954_des2ep1>; ++ vin5_ti9x4_des2ep1: endpoint@1 { ++ remote-endpoint = <&ti9x4_des2ep1>; + }; + }; + }; @@ -16410,8 +16447,8 @@ index 0000000..df27324 + vin6_max9286_des2ep2: endpoint@0 { + remote-endpoint = <&max9286_des2ep2>; + }; -+ vin6_ti964_des2ep2: endpoint@1 { -+ remote-endpoint = <&ti964_des2ep2>; ++ vin6_ti9x4_des2ep2: endpoint@1 { ++ remote-endpoint = <&ti9x4_des2ep2>; + }; + }; + }; @@ -16439,8 +16476,8 @@ index 0000000..df27324 + vin7_max9286_des2ep3: endpoint@0 { + remote-endpoint = <&max9286_des2ep3>; + }; -+ vin7_ti964_des2ep3: endpoint@1 { -+ remote-endpoint = <&ti964_des2ep3>; ++ vin7_ti9x4_des2ep3: endpoint@1 { ++ remote-endpoint = <&ti9x4_des2ep3>; + }; + }; + }; @@ -16481,10 +16518,10 @@ index 0000000..df27324 +}; diff --git a/arch/arm64/boot/dts/renesas/ulcb-vb.dtsi b/arch/arm64/boot/dts/renesas/ulcb-vb.dtsi new file mode 100644 -index 0000000..ab52fff +index 0000000..07594447 --- /dev/null +++ b/arch/arm64/boot/dts/renesas/ulcb-vb.dtsi -@@ -0,0 +1,1770 @@ +@@ -0,0 +1,1678 @@ +/* + * Device Tree Source for the ULCB Videobox board + * @@ -17013,11 +17050,8 @@ index 0000000..ab52fff + ov106xx_max9286_des0ep0: endpoint@0 { + remote-endpoint = <&max9286_des0ep0>; + }; -+ ov106xx_ti964_des0ep0: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep0>; -+ }; -+ ov106xx_ti954_des0ep0: endpoint@2 { -+ remote-endpoint = <&ti954_des0ep0>; ++ ov106xx_ti9x4_des0ep0: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep0>; + }; + }; + }; @@ -17037,11 +17071,8 @@ index 0000000..ab52fff + ov106xx_max9286_des0ep1: endpoint@0 { + remote-endpoint = <&max9286_des0ep1>; + }; -+ ov106xx_ti964_des0ep1: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep1>; -+ }; -+ ov106xx_ti954_des0ep1: endpoint@2 { -+ remote-endpoint = <&ti954_des0ep1>; ++ ov106xx_ti9x4_des0ep1: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep1>; + }; + }; + }; @@ -17061,8 +17092,8 @@ index 0000000..ab52fff + ov106xx_max9286_des0ep2: endpoint@0 { + remote-endpoint = <&max9286_des0ep2>; + }; -+ ov106xx_ti964_des0ep2: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep2>; ++ ov106xx_ti9x4_des0ep2: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep2>; + }; + }; + }; @@ -17082,15 +17113,15 @@ index 0000000..ab52fff + ov106xx_max9286_des0ep3: endpoint@0 { + remote-endpoint = <&max9286_des0ep3>; + }; -+ ov106xx_ti964_des0ep3: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep3>; ++ ov106xx_ti9x4_des0ep3: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep3>; + }; + }; + }; + -+ /* DS90UB964 @ 0x3a */ -+ ti964-ti9x3@0 { -+ compatible = "ti,ti964-ti9x3"; ++ /* DS90UB9x4 @ 0x3a */ ++ ti9x4@0 { ++ compatible = "ti,ti9x4"; + reg = <0x3a>; + ti,links = <4>; + ti,lanes = <4>; @@ -17102,63 +17133,29 @@ index 0000000..ab52fff + POC3-supply = <&pwr3A>; + + port@0 { -+ ti964_des0ep0: endpoint@0 { ++ ti9x4_des0ep0: endpoint@0 { + ti9x3-addr = <0x0c>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in0>; + }; -+ ti964_des0ep1: endpoint@1 { ++ ti9x4_des0ep1: endpoint@1 { + ti9x3-addr = <0x0d>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in1>; + }; -+ ti964_des0ep2: endpoint@2 { ++ ti9x4_des0ep2: endpoint@2 { + ti9x3-addr = <0x0e>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in2>; + }; -+ ti964_des0ep3: endpoint@3 { ++ ti9x4_des0ep3: endpoint@3 { + ti9x3-addr = <0x0f>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in3>; + }; + }; + port@1 { -+ ti964_csi0ep0: endpoint { -+ csi-rate = <1450>; -+ remote-endpoint = <&csi2_40_ep>; -+ }; -+ }; -+ }; -+ -+ /* DS90UB954 @ 0x38 */ -+ ti954-ti9x3@0 { -+ compatible = "ti,ti954-ti9x3"; -+ reg = <0x38>; -+ /* gpios = <&gpio_exp_a_5c 10 GPIO_ACTIVE_HIGH>; */ -+ ti,links = <2>; -+ ti,lanes = <4>; -+ ti,forwarding-mode = "round-robin"; -+ ti,cable-mode = "stp"; -+ POC0-supply = <&pwr0A>; -+ POC1-supply = <&pwr1A>; -+ POC2-supply = <&pwr2A>; -+ POC3-supply = <&pwr3A>; -+ -+ port@0 { -+ ti954_des0ep0: endpoint@0 { -+ ti9x3-addr = <0x0c>; -+ dvp-order = <0>; -+ remote-endpoint = <&ov106xx_in0>; -+ }; -+ ti954_des0ep1: endpoint@1 { -+ ti9x3-addr = <0x0d>; -+ dvp-order = <0>; -+ remote-endpoint = <&ov106xx_in1>; -+ }; -+ }; -+ port@1 { -+ ti954_csi0ep0: endpoint { ++ ti9x4_csi0ep0: endpoint { + csi-rate = <1450>; + remote-endpoint = <&csi2_40_ep>; + }; @@ -17231,11 +17228,8 @@ index 0000000..ab52fff + ov106xx_max9286_des1ep0: endpoint@0 { + remote-endpoint = <&max9286_des1ep0>; + }; -+ ov106xx_ti964_des1ep0: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep0>; -+ }; -+ ov106xx_ti954_des1ep0: endpoint@2 { -+ remote-endpoint = <&ti954_des1ep0>; ++ ov106xx_ti9x4_des1ep0: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep0>; + }; + }; + }; @@ -17255,11 +17249,8 @@ index 0000000..ab52fff + ov106xx_max9286_des1ep1: endpoint@0 { + remote-endpoint = <&max9286_des1ep1>; + }; -+ ov106xx_ti964_des1ep1: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep1>; -+ }; -+ ov106xx_ti954_des1ep1: endpoint@2 { -+ remote-endpoint = <&ti954_des1ep1>; ++ ov106xx_ti9x4_des1ep1: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep1>; + }; + }; + }; @@ -17279,8 +17270,8 @@ index 0000000..ab52fff + ov106xx_max9286_des1ep2: endpoint@0 { + remote-endpoint = <&max9286_des1ep2>; + }; -+ ov106xx_ti964_des1ep2: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep2>; ++ ov106xx_ti9x4_des1ep2: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep2>; + }; + }; + }; @@ -17300,15 +17291,15 @@ index 0000000..ab52fff + ov106xx_max9286_des1ep3: endpoint@0 { + remote-endpoint = <&max9286_des1ep3>; + }; -+ ov106xx_ti964_des1ep3: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep3>; ++ ov106xx_ti9x4_des1ep3: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep3>; + }; + }; + }; + -+ /* DS90UB964 @ 0x3a */ -+ ti964-ti9x3@1 { -+ compatible = "ti,ti964-ti9x3"; ++ /* DS90UB9x4 @ 0x3a */ ++ ti9x4@1 { ++ compatible = "ti,ti9x4"; + reg = <0x3a>; + ti,links = <4>; + ti,lanes = <4>; @@ -17320,63 +17311,29 @@ index 0000000..ab52fff + POC3-supply = <&pwr3B>; + + port@0 { -+ ti964_des1ep0: endpoint@0 { ++ ti9x4_des1ep0: endpoint@0 { + ti9x3-addr = <0x0c>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in4>; + }; -+ ti964_des1ep1: endpoint@1 { ++ ti9x4_des1ep1: endpoint@1 { + ti9x3-addr = <0x0d>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in5>; + }; -+ ti964_des1ep2: endpoint@2 { ++ ti9x4_des1ep2: endpoint@2 { + ti9x3-addr = <0x0e>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in6>; + }; -+ ti964_des1ep3: endpoint@3 { ++ ti9x4_des1ep3: endpoint@3 { + ti9x3-addr = <0x0f>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in7>; + }; + }; + port@1 { -+ ti964_csi2ep0: endpoint { -+ csi-rate = <1450>; -+ remote-endpoint = <&csi2_41_ep>; -+ }; -+ }; -+ }; -+ -+ /* DS90UB954 @ 0x38 */ -+ ti954-ti9x3@1 { -+ compatible = "ti,ti954-ti9x3"; -+ reg = <0x38>; -+ /* gpios = <&gpio_exp_b_5c 10 GPIO_ACTIVE_HIGH>; */ -+ ti,links = <2>; -+ ti,lanes = <4>; -+ ti,forwarding-mode = "round-robin"; -+ ti,cable-mode = "stp"; -+ POC0-supply = <&pwr0B>; -+ POC1-supply = <&pwr1B>; -+ POC2-supply = <&pwr2B>; -+ POC3-supply = <&pwr3B>; -+ -+ port@0 { -+ ti954_des1ep0: endpoint@0 { -+ ti9x3-addr = <0x0c>; -+ dvp-order = <0>; -+ remote-endpoint = <&ov106xx_in4>; -+ }; -+ ti954_des1ep1: endpoint@1 { -+ ti9x3-addr = <0x0d>; -+ dvp-order = <0>; -+ remote-endpoint = <&ov106xx_in5>; -+ }; -+ }; -+ port@1 { -+ ti954_csi2ep0: endpoint { ++ ti9x4_csi2ep0: endpoint { + csi-rate = <1450>; + remote-endpoint = <&csi2_41_ep>; + }; @@ -17866,11 +17823,8 @@ index 0000000..ab52fff + vin0_max9286_des0ep0: endpoint@0 { + remote-endpoint = <&max9286_des0ep0>; + }; -+ vin0_ti964_des0ep0: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep0>; -+ }; -+ vin0_ti954_des0ep0: endpoint@2 { -+ remote-endpoint = <&ti954_des0ep0>; ++ vin0_ti9x4_des0ep0: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep0>; + }; + }; + }; @@ -17900,11 +17854,8 @@ index 0000000..ab52fff + vin1_max9286_des0ep1: endpoint@0 { + remote-endpoint = <&max9286_des0ep1>; + }; -+ vin1_ti964_des0ep1: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep1>; -+ }; -+ vin1_ti954_des0ep1: endpoint@2 { -+ remote-endpoint = <&ti954_des0ep1>; ++ vin1_ti9x4_des0ep1: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep1>; + }; + }; + }; @@ -17934,8 +17885,8 @@ index 0000000..ab52fff + vin2_max9286_des0ep2: endpoint@0 { + remote-endpoint = <&max9286_des0ep2>; + }; -+ vin2_ti964_des0ep2: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep2>; ++ vin2_ti9x4_des0ep2: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep2>; + }; + }; + }; @@ -17965,8 +17916,8 @@ index 0000000..ab52fff + vin3_max9286_des0ep3: endpoint@0 { + remote-endpoint = <&max9286_des0ep3>; + }; -+ vin3_ti964_des0ep3: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep3>; ++ vin3_ti9x4_des0ep3: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep3>; + }; + }; + }; @@ -17996,11 +17947,8 @@ index 0000000..ab52fff + vin4_max9286_des1ep0: endpoint@0 { + remote-endpoint = <&max9286_des1ep0>; + }; -+ vin4_ti964_des1ep0: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep0>; -+ }; -+ vin4_ti954_des1ep0: endpoint@2 { -+ remote-endpoint = <&ti954_des1ep0>; ++ vin4_ti9x4_des1ep0: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep0>; + }; + }; + }; @@ -18030,11 +17978,8 @@ index 0000000..ab52fff + vin5_max9286_des1ep1: endpoint@0 { + remote-endpoint = <&max9286_des1ep1>; + }; -+ vin5_ti964_des1ep1: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep1>; -+ }; -+ vin5_ti954_des1ep1: endpoint@2 { -+ remote-endpoint = <&ti954_des1ep1>; ++ vin5_ti9x4_des1ep1: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep1>; + }; + }; + }; @@ -18064,8 +18009,8 @@ index 0000000..ab52fff + vin6_max9286_des1ep2: endpoint@0 { + remote-endpoint = <&max9286_des1ep2>; + }; -+ vin6_ti964_des1ep2: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep2>; ++ vin6_ti9x4_des1ep2: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep2>; + }; + }; + }; @@ -18095,8 +18040,8 @@ index 0000000..ab52fff + vin7_max9286_des1ep3: endpoint@0 { + remote-endpoint = <&max9286_des1ep3>; + }; -+ vin7_ti964_des1ep3: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep3>; ++ vin7_ti9x4_des1ep3: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep3>; + }; + }; + }; @@ -18257,10 +18202,10 @@ index 0000000..ab52fff +//#include "ulcb-vb-cn12.dtsi" diff --git a/arch/arm64/boot/dts/renesas/ulcb-vb2.dtsi b/arch/arm64/boot/dts/renesas/ulcb-vb2.dtsi new file mode 100644 -index 0000000..72045a7 +index 0000000..b0145a2 --- /dev/null +++ b/arch/arm64/boot/dts/renesas/ulcb-vb2.dtsi -@@ -0,0 +1,1820 @@ +@@ -0,0 +1,1724 @@ +/* + * Device Tree Source for the ULCB Videobox V2 board + * @@ -18807,11 +18752,8 @@ index 0000000..72045a7 + ov106xx_max9286_des0ep0: endpoint@0 { + remote-endpoint = <&max9286_des0ep0>; + }; -+ ov106xx_ti964_des0ep0: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep0>; -+ }; -+ ov106xx_ti954_des0ep0: endpoint@2 { -+ remote-endpoint = <&ti954_des0ep0>; ++ ov106xx_ti9x4_des0ep0: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep0>; + }; + }; + }; @@ -18831,11 +18773,8 @@ index 0000000..72045a7 + ov106xx_max9286_des0ep1: endpoint@0 { + remote-endpoint = <&max9286_des0ep1>; + }; -+ ov106xx_ti964_des0ep1: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep1>; -+ }; -+ ov106xx_ti954_des0ep1: endpoint@2 { -+ remote-endpoint = <&ti954_des0ep1>; ++ ov106xx_ti9x4_des0ep1: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep1>; + }; + }; + }; @@ -18855,8 +18794,8 @@ index 0000000..72045a7 + ov106xx_max9286_des0ep2: endpoint@0 { + remote-endpoint = <&max9286_des0ep2>; + }; -+ ov106xx_ti964_des0ep2: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep2>; ++ ov106xx_ti9x4_des0ep2: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep2>; + }; + }; + }; @@ -18876,15 +18815,15 @@ index 0000000..72045a7 + ov106xx_max9286_des0ep3: endpoint@0 { + remote-endpoint = <&max9286_des0ep3>; + }; -+ ov106xx_ti964_des0ep3: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep3>; ++ ov106xx_ti9x4_des0ep3: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep3>; + }; + }; + }; + -+ /* DS90UB964 @ 0x3a */ -+ ti964-ti9x3@0 { -+ compatible = "ti,ti964-ti9x3"; ++ /* DS90UB9x4 @ 0x3a */ ++ ti9x4@0 { ++ compatible = "ti,ti9x4"; + reg = <0x3a>; + ti,links = <4>; + ti,lanes = <4>; @@ -18896,63 +18835,29 @@ index 0000000..72045a7 + POC3-supply = <&pwr3A>; + + port@0 { -+ ti964_des0ep0: endpoint@0 { ++ ti9x4_des0ep0: endpoint@0 { + ti9x3-addr = <0x0c>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in0>; + }; -+ ti964_des0ep1: endpoint@1 { ++ ti9x4_des0ep1: endpoint@1 { + ti9x3-addr = <0x0d>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in1>; + }; -+ ti964_des0ep2: endpoint@2 { ++ ti9x4_des0ep2: endpoint@2 { + ti9x3-addr = <0x0e>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in2>; + }; -+ ti964_des0ep3: endpoint@3 { ++ ti9x4_des0ep3: endpoint@3 { + ti9x3-addr = <0x0f>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in3>; + }; + }; + port@1 { -+ ti964_csi0ep0: endpoint { -+ csi-rate = <1450>; -+ remote-endpoint = <&csi2_40_ep>; -+ }; -+ }; -+ }; -+ -+ /* DS90UB954 @ 0x38 */ -+ ti954-ti9x3@0 { -+ compatible = "ti,ti954-ti9x3"; -+ reg = <0x38>; -+ /* gpios = <&gpio_exp_a_5c 10 GPIO_ACTIVE_HIGH>; */ -+ ti,links = <2>; -+ ti,lanes = <4>; -+ ti,forwarding-mode = "round-robin"; -+ ti,cable-mode = "stp"; -+ POC0-supply = <&pwr0A>; -+ POC1-supply = <&pwr1A>; -+ POC2-supply = <&pwr2A>; -+ POC3-supply = <&pwr3A>; -+ -+ port@0 { -+ ti954_des0ep0: endpoint@0 { -+ ti9x3-addr = <0x0c>; -+ dvp-order = <0>; -+ remote-endpoint = <&ov106xx_in0>; -+ }; -+ ti954_des0ep1: endpoint@1 { -+ ti9x3-addr = <0x0d>; -+ dvp-order = <0>; -+ remote-endpoint = <&ov106xx_in1>; -+ }; -+ }; -+ port@1 { -+ ti954_csi0ep0: endpoint { ++ ti9x4_csi0ep0: endpoint { + csi-rate = <1450>; + remote-endpoint = <&csi2_40_ep>; + }; @@ -19025,11 +18930,8 @@ index 0000000..72045a7 + ov106xx_max9286_des1ep0: endpoint@0 { + remote-endpoint = <&max9286_des1ep0>; + }; -+ ov106xx_ti964_des1ep0: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep0>; -+ }; -+ ov106xx_ti954_des1ep0: endpoint@2 { -+ remote-endpoint = <&ti954_des1ep0>; ++ ov106xx_ti9x4_des1ep0: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep0>; + }; + }; + }; @@ -19049,11 +18951,8 @@ index 0000000..72045a7 + ov106xx_max9286_des1ep1: endpoint@0 { + remote-endpoint = <&max9286_des1ep1>; + }; -+ ov106xx_ti964_des1ep1: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep1>; -+ }; -+ ov106xx_ti954_des1ep1: endpoint@2 { -+ remote-endpoint = <&ti954_des1ep1>; ++ ov106xx_ti9x4_des1ep1: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep1>; + }; + }; + }; @@ -19073,8 +18972,8 @@ index 0000000..72045a7 + ov106xx_max9286_des1ep2: endpoint@0 { + remote-endpoint = <&max9286_des1ep2>; + }; -+ ov106xx_ti964_des1ep2: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep2>; ++ ov106xx_ti9x4_des1ep2: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep2>; + }; + }; + }; @@ -19094,15 +18993,15 @@ index 0000000..72045a7 + ov106xx_max9286_des1ep3: endpoint@0 { + remote-endpoint = <&max9286_des1ep3>; + }; -+ ov106xx_ti964_des1ep3: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep3>; ++ ov106xx_ti9x4_des1ep3: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep3>; + }; + }; + }; + -+ /* DS90UB964 @ 0x3a */ -+ ti964-ti9x3@1 { -+ compatible = "ti,ti964-ti9x3"; ++ /* DS90UB9x4 @ 0x3a */ ++ ti9x4@1 { ++ compatible = "ti,ti9x4"; + reg = <0x3a>; + ti,links = <4>; + ti,lanes = <4>; @@ -19114,63 +19013,29 @@ index 0000000..72045a7 + POC3-supply = <&pwr3B>; + + port@0 { -+ ti964_des1ep0: endpoint@0 { ++ ti9x4_des1ep0: endpoint@0 { + ti9x3-addr = <0x0c>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in4>; + }; -+ ti964_des1ep1: endpoint@1 { ++ ti9x4_des1ep1: endpoint@1 { + ti9x3-addr = <0x0d>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in5>; + }; -+ ti964_des1ep2: endpoint@2 { ++ ti9x4_des1ep2: endpoint@2 { + ti9x3-addr = <0x0e>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in6>; + }; -+ ti964_des1ep3: endpoint@3 { ++ ti9x4_des1ep3: endpoint@3 { + ti9x3-addr = <0x0f>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in7>; + }; + }; + port@1 { -+ ti964_csi2ep0: endpoint { -+ csi-rate = <1450>; -+ remote-endpoint = <&csi2_41_ep>; -+ }; -+ }; -+ }; -+ -+ /* DS90UB954 @ 0x38 */ -+ ti954-ti9x3@1 { -+ compatible = "ti,ti954-ti9x3"; -+ reg = <0x38>; -+ /* gpios = <&gpio_exp_b_5c 10 GPIO_ACTIVE_HIGH>; */ -+ ti,links = <2>; -+ ti,lanes = <4>; -+ ti,forwarding-mode = "round-robin"; -+ ti,cable-mode = "stp"; -+ POC0-supply = <&pwr0B>; -+ POC1-supply = <&pwr1B>; -+ POC2-supply = <&pwr2B>; -+ POC3-supply = <&pwr3B>; -+ -+ port@0 { -+ ti954_des1ep0: endpoint@0 { -+ ti9x3-addr = <0x0c>; -+ dvp-order = <0>; -+ remote-endpoint = <&ov106xx_in4>; -+ }; -+ ti954_des1ep1: endpoint@1 { -+ ti9x3-addr = <0x0d>; -+ dvp-order = <0>; -+ remote-endpoint = <&ov106xx_in5>; -+ }; -+ }; -+ port@1 { -+ ti954_csi2ep0: endpoint { ++ ti9x4_csi2ep0: endpoint { + csi-rate = <1450>; + remote-endpoint = <&csi2_41_ep>; + }; @@ -19680,11 +19545,8 @@ index 0000000..72045a7 + vin0_max9286_des0ep0: endpoint@0 { + remote-endpoint = <&max9286_des0ep0>; + }; -+ vin0_ti964_des0ep0: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep0>; -+ }; -+ vin0_ti954_des0ep0: endpoint@2 { -+ remote-endpoint = <&ti954_des0ep0>; ++ vin0_ti9x4_des0ep0: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep0>; + }; + }; + }; @@ -19714,11 +19576,8 @@ index 0000000..72045a7 + vin1_max9286_des0ep1: endpoint@0 { + remote-endpoint = <&max9286_des0ep1>; + }; -+ vin1_ti964_des0ep1: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep1>; -+ }; -+ vin1_ti954_des0ep1: endpoint@2 { -+ remote-endpoint = <&ti954_des0ep1>; ++ vin1_ti9x4_des0ep1: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep1>; + }; + }; + }; @@ -19748,8 +19607,8 @@ index 0000000..72045a7 + vin2_max9286_des0ep2: endpoint@0 { + remote-endpoint = <&max9286_des0ep2>; + }; -+ vin2_ti964_des0ep2: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep2>; ++ vin2_ti9x4_des0ep2: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep2>; + }; + }; + }; @@ -19779,8 +19638,8 @@ index 0000000..72045a7 + vin3_max9286_des0ep3: endpoint@0 { + remote-endpoint = <&max9286_des0ep3>; + }; -+ vin3_ti964_des0ep3: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep3>; ++ vin3_ti9x4_des0ep3: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep3>; + }; + }; + }; @@ -19810,11 +19669,8 @@ index 0000000..72045a7 + vin4_max9286_des1ep0: endpoint@0 { + remote-endpoint = <&max9286_des1ep0>; + }; -+ vin4_ti964_des1ep0: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep0>; -+ }; -+ vin4_ti954_des1ep0: endpoint@2 { -+ remote-endpoint = <&ti954_des1ep0>; ++ vin4_ti9x4_des1ep0: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep0>; + }; + }; + }; @@ -19844,11 +19700,8 @@ index 0000000..72045a7 + vin5_max9286_des1ep1: endpoint@0 { + remote-endpoint = <&max9286_des1ep1>; + }; -+ vin5_ti964_des1ep1: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep1>; -+ }; -+ vin5_ti954_des1ep1: endpoint@2 { -+ remote-endpoint = <&ti954_des1ep1>; ++ vin5_ti9x4_des1ep1: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep1>; + }; + }; + }; @@ -19878,8 +19731,8 @@ index 0000000..72045a7 + vin6_max9286_des1ep2: endpoint@0 { + remote-endpoint = <&max9286_des1ep2>; + }; -+ vin6_ti964_des1ep2: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep2>; ++ vin6_ti9x4_des1ep2: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep2>; + }; + }; + }; @@ -19909,8 +19762,8 @@ index 0000000..72045a7 + vin7_max9286_des1ep3: endpoint@0 { + remote-endpoint = <&max9286_des1ep3>; + }; -+ vin7_ti964_des1ep3: endpoint@1 { -+ remote-endpoint = <&ti964_des1ep3>; ++ vin7_ti9x4_des1ep3: endpoint@1 { ++ remote-endpoint = <&ti9x4_des1ep3>; + }; + }; + }; @@ -20083,7 +19936,7 @@ index 0000000..72045a7 +//#include "ulcb-vb2-cn12.dtsi" diff --git a/arch/arm64/boot/dts/renesas/ulcb-vbm.dtsi b/arch/arm64/boot/dts/renesas/ulcb-vbm.dtsi new file mode 100644 -index 0000000..2be4a7c +index 0000000..bc36e95 --- /dev/null +++ b/arch/arm64/boot/dts/renesas/ulcb-vbm.dtsi @@ -0,0 +1,577 @@ @@ -20281,8 +20134,8 @@ index 0000000..2be4a7c + ov106xx_max9286_des0ep0: endpoint@0 { + remote-endpoint = <&max9286_des0ep0>; + }; -+ ov106xx_ti964_des0ep0: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep0>; ++ ov106xx_ti9x4_des0ep0: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep0>; + }; + }; + }; @@ -20302,8 +20155,8 @@ index 0000000..2be4a7c + ov106xx_max9286_des0ep1: endpoint@0 { + remote-endpoint = <&max9286_des0ep1>; + }; -+ ov106xx_ti964_des0ep1: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep1>; ++ ov106xx_ti9x4_des0ep1: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep1>; + }; + }; + }; @@ -20323,8 +20176,8 @@ index 0000000..2be4a7c + ov106xx_max9286_des0ep2: endpoint@0 { + remote-endpoint = <&max9286_des0ep2>; + }; -+ ov106xx_ti964_des0ep2: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep2>; ++ ov106xx_ti9x4_des0ep2: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep2>; + }; + }; + }; @@ -20344,8 +20197,8 @@ index 0000000..2be4a7c + ov106xx_max9286_des0ep3: endpoint@0 { + remote-endpoint = <&max9286_des0ep3>; + }; -+ ov106xx_ti964_des0ep3: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep3>; ++ ov106xx_ti9x4_des0ep3: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep3>; + }; + }; + }; @@ -20393,8 +20246,8 @@ index 0000000..2be4a7c + }; + }; + -+ ti964-ti9x3@0 { -+ compatible = "ti,ti964-ti9x3"; ++ ti9x4@0 { ++ compatible = "ti,ti9x4"; + reg = <0x3a>; + ti,sensor_delay = <350>; + ti,links = <4>; @@ -20407,29 +20260,29 @@ index 0000000..2be4a7c + POC3-supply = <&pwr3>; + + port@0 { -+ ti964_des0ep0: endpoint@0 { ++ ti9x4_des0ep0: endpoint@0 { + ti9x3-addr = <0x0c>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in0>; + }; -+ ti964_des0ep1: endpoint@1 { ++ ti9x4_des0ep1: endpoint@1 { + ti9x3-addr = <0x0d>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in1>; + }; -+ ti964_des0ep2: endpoint@2 { ++ ti9x4_des0ep2: endpoint@2 { + ti9x3-addr = <0x0e>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in2>; + }; -+ ti964_des0ep3: endpoint@3 { ++ ti9x4_des0ep3: endpoint@3 { + ti9x3-addr = <0x0f>; + dvp-order = <0>; + remote-endpoint = <&ov106xx_in3>; + }; + }; + port@1 { -+ ti964_csi0ep0: endpoint { ++ ti9x4_csi0ep0: endpoint { + csi-rate = <1450>; + remote-endpoint = <&csi2_41_ep>; + }; @@ -20564,8 +20417,8 @@ index 0000000..2be4a7c + vin4_max9286_des0ep0: endpoint@0 { + remote-endpoint = <&max9286_des0ep0>; + }; -+ vin4_ti964_des0ep0: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep0>; ++ vin4_ti9x4_des0ep0: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep0>; + }; + }; + }; @@ -20595,8 +20448,8 @@ index 0000000..2be4a7c + vin5_max9286_des0ep1: endpoint@0 { + remote-endpoint = <&max9286_des0ep1>; + }; -+ vin5_ti964_des0ep1: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep1>; ++ vin5_ti9x4_des0ep1: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep1>; + }; + }; + }; @@ -20626,8 +20479,8 @@ index 0000000..2be4a7c + vin6_max9286_des0ep2: endpoint@0 { + remote-endpoint = <&max9286_des0ep2>; + }; -+ vin6_ti964_des0ep2: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep2>; ++ vin6_ti9x4_des0ep2: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep2>; + }; + }; + }; @@ -20657,8 +20510,8 @@ index 0000000..2be4a7c + vin7_max9286_des0ep3: endpoint@0 { + remote-endpoint = <&max9286_des0ep3>; + }; -+ vin7_ti964_des0ep3: endpoint@1 { -+ remote-endpoint = <&ti964_des0ep3>; ++ vin7_ti9x4_des0ep3: endpoint@1 { ++ remote-endpoint = <&ti9x4_des0ep3>; + }; + }; + }; diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/condor.cfg b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/condor.cfg index c32c426..9b2a6a9 100644 --- a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/condor.cfg +++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/condor.cfg @@ -18,7 +18,7 @@ CONFIG_VIDEO_RCAR_CSI2_LEGACY=y CONFIG_SOC_CAMERA=y CONFIG_SOC_CAMERA_SCALE_CROP=y CONFIG_SOC_CAMERA_PLATFORM=y -CONFIG_SOC_CAMERA_MAX9286_MAX9271=y +CONFIG_SOC_CAMERA_MAX9286=y CONFIG_SOC_CAMERA_OV106XX=y CONFIG_VIDEO_RENESAS_IMR=y CONFIG_INPUT_TOUCHSCREEN=y diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/eagle.cfg b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/eagle.cfg index ce08b0d..f6ae11f 100644 --- a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/eagle.cfg +++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/eagle.cfg @@ -18,7 +18,7 @@ CONFIG_VIDEO_RCAR_CSI2_LEGACY=y CONFIG_SOC_CAMERA=y CONFIG_SOC_CAMERA_SCALE_CROP=y CONFIG_SOC_CAMERA_PLATFORM=y -CONFIG_SOC_CAMERA_MAX9286_MAX9271=y +CONFIG_SOC_CAMERA_MAX9286=y CONFIG_SOC_CAMERA_OV106XX=y CONFIG_VIDEO_RENESAS_IMR=y CONFIG_INPUT_TOUCHSCREEN=y diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/salvator-x.cfg b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/salvator-x.cfg index a42b74c..36c6103 100644 --- a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/salvator-x.cfg +++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/salvator-x.cfg @@ -17,7 +17,7 @@ CONFIG_VIDEO_RCAR_CSI2_LEGACY=y CONFIG_SOC_CAMERA=y CONFIG_SOC_CAMERA_SCALE_CROP=y CONFIG_SOC_CAMERA_PLATFORM=y -CONFIG_SOC_CAMERA_MAX9286_MAX9271=y +CONFIG_SOC_CAMERA_MAX9286=y CONFIG_SOC_CAMERA_OV106XX=y CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_PLATFORM=y diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/ulcb.cfg b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/ulcb.cfg index ed9fcb8..49f841f 100644 --- a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/ulcb.cfg +++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/ulcb.cfg @@ -27,9 +27,8 @@ CONFIG_VIDEO_RCAR_CSI2_LEGACY=y CONFIG_SOC_CAMERA=y CONFIG_SOC_CAMERA_SCALE_CROP=y CONFIG_SOC_CAMERA_PLATFORM=y -CONFIG_SOC_CAMERA_MAX9286_MAX9271=y -CONFIG_SOC_CAMERA_TI964_TI9X3=y -CONFIG_SOC_CAMERA_TI954_TI9X3=y +CONFIG_SOC_CAMERA_MAX9286=y +CONFIG_SOC_CAMERA_TI9X4=y CONFIG_SOC_CAMERA_OV106XX=y CONFIG_SOC_CAMERA_OV5647=y CONFIG_SOC_CAMERA_OV5642=y diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/v3msk.cfg b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/v3msk.cfg index 7dea6e2..1a3ba75 100644 --- a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/v3msk.cfg +++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/v3msk.cfg @@ -21,9 +21,8 @@ CONFIG_VIDEO_RCAR_CSI2_LEGACY=y CONFIG_SOC_CAMERA=y CONFIG_SOC_CAMERA_SCALE_CROP=y CONFIG_SOC_CAMERA_PLATFORM=y -CONFIG_SOC_CAMERA_MAX9286_MAX9271=y -CONFIG_SOC_CAMERA_TI964_TI9X3=y -CONFIG_SOC_CAMERA_TI954_TI9X3=y +CONFIG_SOC_CAMERA_MAX9286=y +CONFIG_SOC_CAMERA_TI9X4=y CONFIG_SOC_CAMERA_OV106XX=y CONFIG_VIDEO_RENESAS_IMR=y CONFIG_INPUT_TOUCHSCREEN=y -- cgit 1.2.3-korg