summaryrefslogtreecommitdiffstats
path: root/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0030-Gen3-LVDS-cameras.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0030-Gen3-LVDS-cameras.patch')
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0030-Gen3-LVDS-cameras.patch1554
1 files changed, 867 insertions, 687 deletions
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 <vladimir.barinov@cogentembedded.com>
---
- 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 <vladimir.barinov@cogentembedded.com>
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
+
@@ -96,30 +105,17 @@ index 7704bcf..82da59f 100644
+
+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,9 +1545,592 @@ index 0000000..bcee0e5
+{0x31D0, 0x0001},
+{0x30B0, 0x2002},
+};
+diff --git a/drivers/media/i2c/soc_camera/ar0220.c b/drivers/media/i2c/soc_camera/ar0220.c
+new file mode 100644
+index 0000000..ef2eb51
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/ar0220.c
+@@ -0,0 +1,528 @@
++/*
++ * ON Semiconductor AR0220 sensor camera 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 <linux/delay.h>
++#include <linux/init.h>
++#include <linux/i2c.h>
++#include <linux/module.h>
++#include <linux/videodev2.h>
++
++#include <media/soc_camera.h>
++#include <media/v4l2-common.h>
++#include <media/v4l2-ctrls.h>
++#include <media/v4l2-of.h>
++
++#include "ar0220.h"
++
++#define AR0220_I2C_ADDR 0x10
++//#define AR0220_I2C_ADDR 0x54 // eeprom
++
++#define AR0220_PID 0x3000
++#define AR0220_VERSION_REG 0x0C54
++
++#define AR0220_MEDIA_BUS_FMT MEDIA_BUS_FMT_SBGGR8_1X8
++
++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 inline struct ar0220_priv *to_ar0220(const struct i2c_client *client)
++{
++ return container_of(i2c_get_clientdata(client), struct ar0220_priv, sd);
++}
++
++static int ar0220_set_regs(struct i2c_client *client,
++ const struct ar0220_reg *regs, int nr_regs)
++{
++ int i;
++
++ for (i = 0; i < nr_regs; i++) {
++ if (regs[i].reg == AR0220_DELAY) {
++ mdelay(regs[i].val);
++ continue;
++ }
++
++ reg16_write16(client, regs[i].reg, regs[i].val);
++ }
++
++ return 0;
++}
++
++static int ar0220_s_stream(struct v4l2_subdev *sd, int enable)
++{
++ return 0;
++}
++
++static int ar0220_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 ar0220_priv *priv = to_ar0220(client);
++
++ 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 int ar0220_set_fmt(struct v4l2_subdev *sd,
++ struct v4l2_subdev_pad_config *cfg,
++ struct v4l2_subdev_format *format)
++{
++ struct v4l2_mbus_framefmt *mf = &format->format;
++
++ mf->code = AR0220_MEDIA_BUS_FMT;
++ mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
++ mf->field = V4L2_FIELD_NONE;
++
++ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
++ cfg->try_fmt = *mf;
++
++ return 0;
++}
++
++static int ar0220_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;
++
++ code->code = AR0220_MEDIA_BUS_FMT;
++
++ return 0;
++}
++
++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);
++
++ 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 ar0220_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 ar0220_priv *priv = to_ar0220(client);
++
++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE ||
++ sel->target != V4L2_SEL_TGT_CROP)
++ return -EINVAL;
++
++ rect->left = ALIGN(rect->left, 2);
++ rect->top = ALIGN(rect->top, 2);
++ rect->width = ALIGN(rect->width, 2);
++ rect->height = ALIGN(rect->height, 2);
++
++ if ((rect->left + rect->width > AR0220_MAX_WIDTH) ||
++ (rect->top + rect->height > AR0220_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 ar0220_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 ar0220_priv *priv = to_ar0220(client);
++
++ if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
++ return -EINVAL;
++
++ 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;
++ }
++}
++
++static int ar0220_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 ar0220_g_register(struct v4l2_subdev *sd,
++ struct v4l2_dbg_register *reg)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++ int ret;
++ u16 val = 0;
++
++ ret = reg16_read16(client, (u16)reg->reg, &val);
++ if (ret < 0)
++ return ret;
++
++ reg->val = val;
++ reg->size = sizeof(u16);
++
++ return 0;
++}
++
++static int ar0220_s_register(struct v4l2_subdev *sd,
++ const struct v4l2_dbg_register *reg)
++{
++ struct i2c_client *client = v4l2_get_subdevdata(sd);
++
++ return reg16_write16(client, (u16)reg->reg, (u16)reg->val);
++}
++#endif
++
++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 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 (!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 ret;
++}
++
++static const struct v4l2_ctrl_ops ar0220_ctrl_ops = {
++ .s_ctrl = ar0220_s_ctrl,
++};
++
++static struct v4l2_subdev_video_ops ar0220_video_ops = {
++ .s_stream = ar0220_s_stream,
++ .g_mbus_config = ar0220_g_mbus_config,
++};
++
++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 ar0220_subdev_ops = {
++ .core = &ar0220_core_ops,
++ .video = &ar0220_video_ops,
++ .pad = &ar0220_subdev_pad_ops,
++};
++
++static void ar0220_otp_id_read(struct i2c_client *client)
++{
++}
++
++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);
++
++ 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_ar0220, S_IRUGO, ar0220_otp_id_show, NULL);
++
++static int ar0220_initialize(struct i2c_client *client)
++{
++ struct ar0220_priv *priv = to_ar0220(client);
++ u16 val = 0;
++ u16 pid = 0;
++ int ret = 0;
++
++ /* check and show model ID */
++ reg16_read16(client, AR0220_PID, &pid);
++
++ if (pid != AR0220_VERSION_REG) {
++ dev_dbg(&client->dev, "Product ID error %x\n", pid);
++ ret = -ENODEV;
++ goto err;
++ }
++
++ /* Program wizard registers */
++ ar0220_set_regs(client, ar0220_regs_wizard, ARRAY_SIZE(ar0220_regs_wizard));
++
++ /* 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
++
++ /* Read OTP IDs */
++ ar0220_otp_id_read(client);
++
++ 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 int ar0220_parse_dt(struct device_node *np, struct ar0220_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);
++ if (!endpoint)
++ break;
++
++ of_node_put(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\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 ar0220_probe(struct i2c_client *client,
++ const struct i2c_device_id *did)
++{
++ struct ar0220_priv *priv;
++ int ret;
++
++ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ v4l2_i2c_subdev_init(&priv->sd, client, &ar0220_subdev_ops);
++ priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
++
++ 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;
++
++ ret = priv->hdl.error;
++ if (ret)
++ goto cleanup;
++
++ v4l2_ctrl_handler_setup(&priv->hdl);
++
++ 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;
++
++ ret = ar0220_parse_dt(client->dev.of_node, priv);
++ if (ret)
++ goto cleanup;
++
++ ret = ar0220_initialize(client);
++ if (ret < 0)
++ goto cleanup;
++
++ priv->rect.left = 0;
++ priv->rect.top = 0;
++ priv->rect.width = AR0220_MAX_WIDTH;
++ priv->rect.height = AR0220_MAX_HEIGHT;
++
++ ret = v4l2_async_register_subdev(&priv->sd);
++ if (ret)
++ goto cleanup;
++
++ 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 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(i2c, ar0220_id);
++
++static const struct of_device_id ar0220_of_ids[] = {
++ { .compatible = "aptina,ar0220", },
++ { }
++};
++MODULE_DEVICE_TABLE(of, ar0220_of_ids);
++
++static struct i2c_driver ar0220_i2c_driver = {
++ .driver = {
++ .name = "ar0220",
++ .of_match_table = ar0220_of_ids,
++ },
++ .probe = ar0220_probe,
++ .remove = ar0220_remove,
++ .id_table = ar0220_id,
++};
++
++module_i2c_driver(ar0220_i2c_driver);
++
++MODULE_DESCRIPTION("SoC Camera driver for AR0220");
++MODULE_AUTHOR("Vladimir Barinov");
++MODULE_LICENSE("GPL");
++#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..29987a6
+--- /dev/null
++++ b/drivers/media/i2c/soc_camera/ar0220.h
+@@ -0,0 +1,43 @@
++/*
++ * ON Semiconductor AR0220 sensor camera wizard 1820x940@44/RCCB/BT656
++ *
++ * 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
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ */
++
++//#define AR0220_DISPLAY_PATTERN_FIXED
++//#define AR0220_DISPLAY_PATTERN_COLOR_BAR
++
++#define AR0220_MAX_WIDTH 3648 // (1820*2=3640) <- must be multiple of 16 - requred by R-CAR VIN
++#define AR0220_MAX_HEIGHT 944
++
++#define AR0220_DELAY 0xffff
++
++struct ar0220_reg {
++ u16 reg;
++ u16 val;
++};
++
++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..989c782
+index 0000000..4dd80f5
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/max9286.c
@@ -0,0 +1,697 @@
@@ -1642,35 +2204,35 @@ index 0000000..989c782
+
+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 */");
++MODULE_PARM_DESC(poc_trig, " Use PoC triggering during reverse channel setup. Useful on systems with dedicated PoC and unstable ser-des lock");
+
+static int him;
+module_param(him, int, 0644);
-+MODULE_PARM_DESC(him, " Use High-Immunity mode (default: leagacy mode) */");
++MODULE_PARM_DESC(him, " Use High-Immunity mode (default: leagacy mode)");
+
+static int fsync_period;
+module_param(fsync_period, int, 0644);
-+MODULE_PARM_DESC(fsync_period, " Frame sync period (default: 3.2MHz) */");
++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) */");
++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) */");
++MODULE_PARM_DESC(vsync, " VSYNC invertion (default: 1 - inverted)");
+
+static int gpio_resetb;
+module_param(gpio_resetb, int, 0644);
-+MODULE_PARM_DESC(gpio_resetb, " Serializer GPIO reset (default: 0 - not used) */");
++MODULE_PARM_DESC(gpio_resetb, " Serializer GPIO reset (default: 0 - not used)");
+
+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) */");
++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) */");
++MODULE_PARM_DESC(poc_delay, " Delay in ms after POC enable (default: 0 ms)");
+
+static char* ser_name(int id)
+{
@@ -4491,10 +5053,10 @@ index 0000000..4c3515a
+#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
+index 0000000..1dca809
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/ov106xx.c
-@@ -0,0 +1,117 @@
+@@ -0,0 +1,128 @@
+/*
+ * OmniVision ov10635/ov490-ov10640/ov495-ov2775 sensor camera driver
+ *
@@ -4510,6 +5072,7 @@ index 0000000..4c797f9
+#include "ov490_ov10640.c"
+#include "ov495_ov2775.c"
+#include "ar0132.c"
++#include "ar0220.c"
+#include "ap0101_ar014x.c"
+
+static enum {
@@ -4517,6 +5080,7 @@ index 0000000..4c797f9
+ ID_OV490_OV10640,
+ ID_OV495_OV2775,
+ ID_AR0132,
++ ID_AR0220,
+ ID_AP0101_AR014X,
+} chip_id;
+
@@ -4550,6 +5114,12 @@ index 0000000..4c797f9
+ 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;
@@ -4577,6 +5147,9 @@ index 0000000..4c797f9
+ case ID_AR0132:
+ ar0132_remove(client);
+ break;
++ case ID_AR0220:
++ ar0220_remove(client);
++ break;
+ case ID_AP0101_AR014X:
+ ap0101_remove(client);
+ break;
@@ -4609,19 +5182,19 @@ index 0000000..4c797f9
+
+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_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..f1e34a3
+index 0000000..812f367
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/ov490_ov10640.c
-@@ -0,0 +1,1160 @@
+@@ -0,0 +1,1133 @@
+/*
+ * OmniVision ov490-ov10640 sensor camera driver
+ *
-+ * Copyright (C) 2016-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
@@ -4677,8 +5250,7 @@ index 0000000..f1e34a3
+ /* serializers */
+ int max9286_addr;
+ int max9271_addr;
-+ int ti964_addr;
-+ int ti954_addr;
++ int ti9x4_addr;
+ int ti9x3_addr;
+ int port;
+ int gpio_resetb;
@@ -4742,18 +5314,8 @@ index 0000000..f1e34a3
+ 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 */
++ 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 */
@@ -5557,19 +6119,13 @@ index 0000000..f1e34a3
+ }
+
+ 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 OV490\n");
+ return -EINVAL;
+ }
@@ -5585,18 +6141,8 @@ index 0000000..f1e34a3
+ reg8_write(client, 0x0A, OV490_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, 0x6e, 0x9a); /* GPIO0 - fsin, GPIO1 - resetb */
-+ }
-+ 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 */
@@ -5888,10 +6434,10 @@ index 0000000..b22e93e
+};
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..6dc0675
+index 0000000..e53c482
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/ov495_ov2775.c
-@@ -0,0 +1,658 @@
+@@ -0,0 +1,639 @@
+/*
+ * OmniVision ov495-ov2775 sensor camera driver
+ *
@@ -5943,8 +6489,7 @@ index 0000000..6dc0675
+ /* serializers */
+ int max9286_addr;
+ int max9271_addr;
-+ int ti960_addr;
-+ int ti954_addr;
++ int ti9x4_addr;
+ int ti9x3_addr;
+ int port;
+ int gpio_resetb;
@@ -6365,39 +6910,21 @@ index 0000000..6dc0675
+ 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))
-+ 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) {
++ if (!priv->ti9x4_addr) {
+ dev_err(&client->dev, "deserializer does not present for OV495\n");
+ return -EINVAL;
+ }
+
+ /* setup I2C translator address */
+ tmp_addr = client->addr;
-+ if (priv->ti960_addr) {
-+ client->addr = priv->ti960_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, 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 */
@@ -6579,16 +7106,16 @@ index 0000000..3f53689
+{0x8017, 0x1e | (0 << 6)},
+{0x7c10, 0x01}, /* UYVY */
+};
-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/ti9x4.c b/drivers/media/i2c/soc_camera/ti9x4.c
new file mode 100644
-index 0000000..ff84128
+index 0000000..aac892b
--- /dev/null
-+++ b/drivers/media/i2c/soc_camera/ti954_ti9x3.c
-@@ -0,0 +1,439 @@
++++ b/drivers/media/i2c/soc_camera/ti9x4.c
+@@ -0,0 +1,520 @@
+/*
-+ * TI ti954-(ti913/ti953) FPDLinkIII driver
++ * TI DS90UB954/960/964 FPDLinkIII driver
+ *
-+ * Copyright (C) 2017 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
@@ -6609,9 +7136,9 @@ index 0000000..ff84128
+#include <media/v4l2-of.h>
+#include <media/v4l2-subdev.h>
+
-+#include "ti9x4_ti9x3.h"
++#include "ti9x4.h"
+
-+struct ti954_ti9x3_priv {
++struct ti9x4_priv {
+ struct v4l2_subdev sd[4];
+ struct device_node *sd_of_node[4];
+ int des_addr;
@@ -6619,16 +7146,44 @@ index 0000000..ff84128
+ 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 */
-+ int xtal_gpio;
+};
+
++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)");
++
++#ifdef TI954_SILICON_ERRATA
+static int indirect_write(struct i2c_client *client, unsigned int page, u8 reg, u8 val)
+{
+ if (page > 7)
@@ -6641,7 +7196,6 @@ index 0000000..ff84128
+ return 0;
+}
+
-+#if 0
+static int indirect_read(struct i2c_client *client, unsigned int page, u8 reg, u8 *val)
+{
+ if (page > 7)
@@ -6655,13 +7209,9 @@ index 0000000..ff84128
+}
+#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 void ti9x4_read_chipid(struct i2c_client *client)
+{
-+ struct ti954_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]);
@@ -6672,12 +7222,12 @@ index 0000000..ff84128
+ priv->chip_id[5] = '\0';
+}
+
-+static void ti954_ti9x3_initial_setup(struct i2c_client *client)
++static void ti9x4_initial_setup(struct i2c_client *client)
+{
-+ struct ti954_ti9x3_priv *priv = i2c_get_clientdata(client);
++ struct ti9x4_priv *priv = i2c_get_clientdata(client);
+
+ /* Initial setup */
-+ client->addr = priv->des_addr; /* TI954 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 */
@@ -6688,7 +7238,8 @@ index 0000000..ff84128
+ reg8_write(client, 0x1f, 0x00); /* CSI rate 1.5/1.6Gbps */
+ break;
+ case 800: /* REFCLK = 25MHZ */
-+ reg8_write(client, 0x1f, 0x02); /* CSI rate 800Mbps */
++ case 700: /* REFCLK = 22.5MHZ */
++ reg8_write(client, 0x1f, 0x02); /* CSI rate 700/800Mbps */
+ break;
+ case 400: /* REFCLK = 25MHZ */
+ reg8_write(client, 0x1f, 0x03); /* CSI rate 400Mbps */
@@ -6722,7 +7273,7 @@ index 0000000..ff84128
+ 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
+}
@@ -6730,456 +7281,73 @@ index 0000000..ff84128
+//#define SENSOR_ID 0x30 // ov10635
+//#define SENSOR_ID 0x24 // ov490
+
-+static void ti954_ti9x3_fpdlink3_setup(struct i2c_client *client, int idx)
++static void ti9x4_fpdlink3_setup(struct i2c_client *client, int idx)
+{
-+ struct ti954_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; /* TI954 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 */
-+ 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 */
-+}
-+
-+static int ti954_ti9x3_initialize(struct i2c_client *client)
-+{
-+ struct ti954_ti9x3_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);
-+
-+ ti954_ti9x3_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);
-+ }
-+
-+ ti954_ti9x3_fpdlink3_setup(client, idx);
-+ }
-+
-+ client->addr = priv->des_addr;
-+
-+ return 0;
-+}
-+
-+#ifdef CONFIG_VIDEO_ADV_DEBUG
-+static int ti954_ti9x3_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;
-+ int ret;
-+ u8 val = 0;
-+
-+ ret = reg8_read(client, (u8)reg->reg, &val);
-+ if (ret < 0)
-+ return ret;
-+
-+ reg->val = val;
-+ reg->size = sizeof(u8);
-+
-+ return 0;
-+}
-+
-+static int ti954_ti9x3_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;
-+
-+ return reg8_write(client, (u8)reg->reg, (u8)reg->val);
-+}
-+#endif
-+
-+static int ti954_ti9x3_s_power(struct v4l2_subdev *sd, int on)
-+{
-+ struct ti954_ti9x3_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, 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 */
-+ }
-+
-+ return 0;
-+}
-+
-+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 */
-+
-+ return 0;
-+}
+
-+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 struct v4l2_subdev_ops ti954_ti9x3_subdev_ops = {
-+ .core = &ti954_ti9x3_subdev_core_ops,
-+};
-+
-+static int ti954_ti9x3_parse_dt(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;
-+
-+ if (of_property_read_u32(np, "ti,links", &priv->links))
-+ priv->links = 2;
-+
-+ if (of_property_read_u32(np, "ti,lanes", &priv->lanes))
-+ priv->lanes = 4;
-+
-+ 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);
-+ }
-+
-+ 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;
-+ }
-+
-+ ti954_ti9x3_read_chipid(client);
-+
-+ 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 (!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;
-+
-+ /* module params override dts */
-+ if (poc_delay)
-+ priv->poc_delay = poc_delay;
-+
-+ for (i = 0; ; i++) {
-+ endpoint = of_graph_get_next_endpoint(np, endpoint);
-+ if (!endpoint)
-+ break;
-+
-+ 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;
-+
-+ 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);
-+ }
-+
-+ dvp_order_prop = of_find_property(endpoint, "dvp-order", NULL);
-+ if (dvp_order_prop)
-+ of_update_property(rendpoint, dvp_order_prop);
-+ }
-+
-+ return 0;
-+}
-+
-+static int ti954_ti9x3_probe(struct i2c_client *client,
-+ const struct i2c_device_id *did)
-+{
-+ struct ti954_ti9x3_priv *priv;
-+ int err, i;
-+ char supply_name[10];
-+
-+ 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);
-+
-+ err = ti954_ti9x3_parse_dt(client);
-+ if (err)
-+ goto out;
-+
-+ for (i = 0; i < 4; i++) {
-+ sprintf(supply_name, "POC%d", i);
-+ priv->poc_supply[i] = devm_regulator_get_optional(&client->dev, supply_name);
-+ }
-+
-+ err = ti954_ti9x3_initialize(client);
-+ if (err < 0)
-+ goto out;
-+
-+ 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];
-+
-+ snprintf(priv->sd[i].name, V4L2_SUBDEV_NAME_SIZE, "%s %d-%04x",
-+ client->dev.driver->name, i2c_adapter_id(client->adapter),
-+ client->addr);
-+
-+ err = v4l2_async_register_subdev(&priv->sd[i]);
-+ if (err < 0)
-+ goto out;
-+ }
-+
-+out:
-+ return err;
-+}
-+
-+static int ti954_ti9x3_remove(struct i2c_client *client)
-+{
-+ struct ti954_ti9x3_priv *priv = i2c_get_clientdata(client);
-+ int i;
-+
-+ for (i = 0; i < priv->links; i++) {
-+ v4l2_async_unregister_subdev(&priv->sd[i]);
-+ v4l2_device_unregister_subdev(&priv->sd[i]);
-+ }
-+
-+ return 0;
-+}
-+
-+static const struct of_device_id ti954_ti9x3_dt_ids[] = {
-+ { .compatible = "ti,ti954-ti9x3" },
-+ {},
-+};
-+MODULE_DEVICE_TABLE(of, ti954_ti9x3_dt_ids);
-+
-+static const struct i2c_device_id ti954_ti9x3_id[] = {
-+ { "ti954_ti9x3", 0 },
-+ { }
-+};
-+MODULE_DEVICE_TABLE(i2c, ti954_ti9x3_id);
-+
-+static struct i2c_driver ti954_ti9x3_i2c_driver = {
-+ .driver = {
-+ .name = "ti954_ti9x3",
-+ .of_match_table = of_match_ptr(ti954_ti9x3_dt_ids),
-+ },
-+ .probe = ti954_ti9x3_probe,
-+ .remove = ti954_ti9x3_remove,
-+ .id_table = ti954_ti9x3_id,
-+};
-+
-+module_i2c_driver(ti954_ti9x3_i2c_driver);
-+
-+MODULE_DESCRIPTION("FPDLinkIII driver for TI954-TI9X3");
-+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
-new file mode 100644
-index 0000000..8393392
---- /dev/null
-+++ b/drivers/media/i2c/soc_camera/ti964_ti9x3.c
-@@ -0,0 +1,408 @@
-+/*
-+ * TI (ti964/ti960)-(ti913/ti953) FPDLinkIII driver
-+ *
-+ * 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
-+ * Free Software Foundation; either version 2 of the License, or (at your
-+ * option) any later version.
-+ */
-+
-+#include <linux/delay.h>
-+#include <linux/i2c.h>
-+#include <linux/module.h>
-+#include <linux/notifier.h>
-+#include <linux/of_gpio.h>
-+#include <linux/regulator/consumer.h>
-+#include <linux/videodev2.h>
-+
-+#include <media/v4l2-common.h>
-+#include <media/v4l2-device.h>
-+#include <media/v4l2-of.h>
-+#include <media/v4l2-subdev.h>
-+
-+#include "ti9x4_ti9x3.h"
-+
-+struct ti964_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 */
-+};
-+
-+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 ti964_ti9x3_read_chipid(struct i2c_client *client)
-+{
-+ struct ti964_ti9x3_priv *priv = i2c_get_clientdata(client);
-+
-+ /* 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';
-+}
-+
-+static void ti964_ti9x3_initial_setup(struct i2c_client *client)
-+{
-+ struct ti964_ti9x3_priv *priv = i2c_get_clientdata(client);
-+
-+ /* Initial setup */
-+ client->addr = priv->des_addr; /* TI964 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 */
++ switch (priv->ser_id) {
++ case TI913_ID:
++ reg8_write(client, 0x58, 0x58); /* Back channel: Freq=2.5Mbps */
+ break;
-+ case 800: /* REFCLK = 25MHZ */
-+ case 700: /* REFCLK = 22.5MHZ */
-+ reg8_write(client, 0x1f, 0x02); /* CSI rate 700/800Mbps */
-+ break;
-+ case 400: /* REFCLK = 25MHZ */
-+ reg8_write(client, 0x1f, 0x03); /* CSI rate 400Mbps */
++ case TI953_ID:
++ reg8_write(client, 0x58, 0x5e); /* Back channel: Freq=50Mbps */
+ break;
+ default:
-+ dev_err(&client->dev, "unsupported CSI rate %d\n", priv->csi_rate);
-+ }
-+
-+ 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!!) */
++ break;
+ }
+
-+ 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
-+}
-+
-+//#define SENSOR_ID 0x30 // ov10635
-+//#define SENSOR_ID 0x24 // ov490
-+
-+static void ti964_ti9x3_fpdlink3_setup(struct i2c_client *client, int idx)
-+{
-+ struct ti964_ti9x3_priv *priv = i2c_get_clientdata(client);
-+
-+ /* FPDLinkIII setup */
-+ client->addr = priv->des_addr; /* TI964 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 */
++
++ 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;
}