aboutsummaryrefslogtreecommitdiffstats
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.patch239
1 files changed, 179 insertions, 60 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 aca7198..781e456 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
@@ -11,20 +11,20 @@ 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/ar0132.c | 548 +++++++++++
+ drivers/media/i2c/soc_camera/ar0132.c | 581 +++++++++++
drivers/media/i2c/soc_camera/ar0132.h | 213 ++++
- drivers/media/i2c/soc_camera/max9286_max9271.c | 567 +++++++++++
- drivers/media/i2c/soc_camera/max9286_max9271.h | 243 +++++
- drivers/media/i2c/soc_camera/ov10635.c | 759 ++++++++++++++
+ drivers/media/i2c/soc_camera/max9286_max9271.c | 607 ++++++++++++
+ drivers/media/i2c/soc_camera/max9286_max9271.h | 244 +++++
+ drivers/media/i2c/soc_camera/ov10635.c | 758 ++++++++++++++
drivers/media/i2c/soc_camera/ov10635.h | 1139 ++++++++++++++++++++++
drivers/media/i2c/soc_camera/ov10635_debug.h | 54 +
drivers/media/i2c/soc_camera/ov106xx.c | 106 ++
- drivers/media/i2c/soc_camera/ov490_ov10640.c | 1046 ++++++++++++++++++++
- drivers/media/i2c/soc_camera/ov490_ov10640.h | 88 ++
+ drivers/media/i2c/soc_camera/ov490_ov10640.c | 1064 ++++++++++++++++++++
+ drivers/media/i2c/soc_camera/ov490_ov10640.h | 93 ++
drivers/media/i2c/soc_camera/ov495_ov2775.c | 658 +++++++++++++
drivers/media/i2c/soc_camera/ov495_ov2775.h | 23 +
- drivers/media/i2c/soc_camera/ti954_ti9x3.c | 417 ++++++++
- drivers/media/i2c/soc_camera/ti964_ti9x3.c | 385 ++++++++
+ drivers/media/i2c/soc_camera/ti954_ti9x3.c | 431 ++++++++
+ drivers/media/i2c/soc_camera/ti964_ti9x3.c | 399 ++++++++
drivers/media/i2c/soc_camera/ti9x4_ti9x3.h | 153 +++
drivers/media/platform/soc_camera/rcar_csi2.c | 297 ++++--
drivers/media/platform/soc_camera/rcar_vin.c | 174 +++-
@@ -32,7 +32,7 @@ Signed-off-by: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
drivers/media/platform/soc_camera/soc_mediabus.c | 16 +
include/media/drv-intf/soc_mediabus.h | 3 +
include/media/soc_camera.h | 1 +
- 23 files changed, 6852 insertions(+), 109 deletions(-)
+ 23 files changed, 6976 insertions(+), 109 deletions(-)
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/max9286_max9271.c
@@ -129,10 +129,10 @@ index 6f994f9..7d4c1ab 100644
obj-$(CONFIG_SOC_CAMERA_OV6650) += ov6650.o
diff --git a/drivers/media/i2c/soc_camera/ar0132.c b/drivers/media/i2c/soc_camera/ar0132.c
new file mode 100644
-index 0000000..284c522
+index 0000000..decbf5f
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/ar0132.c
-@@ -0,0 +1,548 @@
+@@ -0,0 +1,581 @@
+/*
+ * Aptina AR0132 sensor camera driver
+ *
@@ -177,6 +177,8 @@ index 0000000..284c522
+ int autogain;
+ int dvp_order;
+ /* serializers */
++ int max9286_addr;
++ int max9271_addr;
+ int ti964_addr;
+ int ti954_addr;
+ int ti9x3_addr;
@@ -191,6 +193,19 @@ index 0000000..284c522
+ return container_of(i2c_get_clientdata(client), struct ar0132_priv, sd);
+}
+
++static void ar0132_s_port(struct i2c_client *client, int fwd_en)
++{
++ struct ar0132_priv *priv = to_ar0132(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 */
++ client->addr = tmp_addr;
++ };
++}
++
+static int ar0132_set_regs(struct i2c_client *client,
+ const struct ar0132_reg *regs, int nr_regs)
+{
@@ -456,6 +471,8 @@ index 0000000..284c522
+ u16 pid = 0;
+ int ret = 0;
+
++ ar0132_s_port(client, 1);
++
+ /* check and show model ID */
+ reg16_read16(client, AR0132_PID, &pid);
+
@@ -479,6 +496,8 @@ index 0000000..284c522
+ dev_info(&client->dev, "ar0132 PID %x, res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n",
+ pid, AR0132_MAX_WIDTH, AR0132_MAX_HEIGHT, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
+err:
++ ar0132_s_port(client, 0);
++
+ return ret;
+}
+
@@ -502,6 +521,11 @@ index 0000000..284c522
+ if (!rendpoint)
+ continue;
+
++ 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;
++
+ 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) &&
@@ -515,13 +539,22 @@ index 0000000..284c522
+ break;
+ }
+
-+ if (!priv->ti964_addr && !priv->ti954_addr) {
-+ dev_err(&client->dev, "deserializer does not present\n");
++ if (!priv->max9286_addr && !priv->ti964_addr && !priv->ti954_addr) {
++ dev_err(&client->dev, "deserializer does not present for AR0132\n");
+ return -EINVAL;
+ }
+
++ ar0132_s_port(client, 1);
++
+ /* setup I2C translator address */
+ tmp_addr = client->addr;
++ if (priv->max9286_addr) {
++ client->addr = priv->max9271_addr; /* Serializer I2C address */
++
++ reg8_write(client, 0x09, tmp_addr << 1); /* Sensor translated I2C address */
++ 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 */
+
@@ -902,10 +935,10 @@ index 0000000..055841d
+};
diff --git a/drivers/media/i2c/soc_camera/max9286_max9271.c b/drivers/media/i2c/soc_camera/max9286_max9271.c
new file mode 100644
-index 0000000..9797d24
+index 0000000..91223a0
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/max9286_max9271.c
-@@ -0,0 +1,567 @@
+@@ -0,0 +1,607 @@
+/*
+ * MAXIM max9286-max9271 GMSL driver
+ *
@@ -920,9 +953,10 @@ index 0000000..9797d24
+#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 <linux/notifier.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
@@ -959,10 +993,12 @@ index 0000000..9797d24
+ u32 csi2_outord;
+ struct i2c_client *client;
+ int max9271_addr_map[4];
++ struct regulator *poc_supply[4]; /* PoC power supply */
+};
+
+static int force_conf_link;
-+
++static int force_poc_trig;
++#ifndef MODULE
+static __init int max9286_max9271_force_conf_link(char *str)
+{
+ /* force configuration link */
@@ -972,6 +1008,16 @@ index 0000000..9797d24
+}
+early_param("force_conf_link", max9286_max9271_force_conf_link);
+
++static __init int max9286_max9271_force_poc_trig(char *str)
++{
++ /* force PoC triggering during reverse channel setup */
++ /* to be used on systems with dedicated PoC and unstable ser-des lock */
++ force_poc_trig = 1;
++ return 0;
++}
++early_param("force_poc_trig", max9286_max9271_force_poc_trig);
++#endif
++
+static void max9286_max9271_preinit(struct i2c_client *client, int addr)
+{
+ client->addr = addr; /* MAX9286-CAMx I2C */
@@ -980,27 +1026,32 @@ index 0000000..9797d24
+ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
+}
+
-+static void max9286_max9271_sensor_reset(struct i2c_client *client, int addr)
++static void max9286_max9271_sensor_reset(struct i2c_client *client, int addr, int reset_on)
+{
+ struct max9286_max9271_priv *priv = i2c_get_clientdata(client);
+
+ if (priv->gpio_resetb < 1 || priv->gpio_resetb > 5)
+ return;
+
-+ /* get out from sensor reset */
++ /* sensor reset/unreset */
+ client->addr = addr; /* MAX9271-CAMx I2C */
-+ reg8_write(client, 0x0f, (0xfe & ~BIT(priv->gpio_resetb)) |
-+ (priv->active_low_resetb ? 0 : BIT(priv->gpio_resetb))); /* set GPIOn value to reset */
++ 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 */
-+ 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 */
+}
+
+static void max9286_max9271_postinit(struct i2c_client *client, int addr)
+{
+ struct max9286_max9271_priv *priv = i2c_get_clientdata(client);
++ int idx;
++
++ 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 */
++
++ client->addr = priv->max9271_addr_map[idx]; /* MAX9271-CAMx I2C */
++ max9286_max9271_sensor_reset(client, client->addr, 0); /* sensor unreset */
++ }
+
+ client->addr = addr; /* MAX9286 I2C */
+ reg8_write(client, 0x0a, 0x00); /* disable reverse control for all cams */
@@ -1016,6 +1067,7 @@ index 0000000..9797d24
+ struct max9286_max9271_priv *priv = i2c_get_clientdata(client);
+ u8 val = 0;
+ int timeout = priv->timeout;
++ char timeout_str[10];
+ int ret = 0;
+
+ /* Reverse channel enable */
@@ -1033,7 +1085,10 @@ index 0000000..9797d24
+ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
+
+ 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, 0x1); /* reverse channel receiver high threshold enable */
++ reg8_write(client, 0x97, 0x5f); /* enable reverse control channel programming (MAX96705-MAX96711 only) */
+ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
+
+ client->addr = priv->des_addr; /* MAX9286-CAMx I2C */
@@ -1041,26 +1096,32 @@ index 0000000..9797d24
+ usleep_range(2000, 2500); /* wait 2ms after any change of reverse channel settings */
+
+ 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 */
-+
-+ client->addr = 0x40; /* MAX9271-CAMx I2C */
+ reg8_read(client, 0x1e, &val); /* read max9271 ID */
-+ if (val == MAX9271_ID || --timeout == 0)
++ if (val == MAX9271_ID || val == MAX96705_ID || --timeout == 0)
+ 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) {
++ if (val == MAX9271_ID || val == MAX96705_ID) {
+ 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 && force_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);
++ }
++ }
+ }
+
-+ max9286_max9271_sensor_reset(client, client->addr); /* sensor reset */
++ max9286_max9271_sensor_reset(client, client->addr, 1); /* sensor reset */
+
+ if (!timeout) {
+ ret = -ETIMEDOUT;
@@ -1072,9 +1133,11 @@ index 0000000..9797d24
+ priv->csi2_outord |= ((hweight8(priv->links_mask) - 1) << (idx * 2));
+
+out:
-+ dev_info(&client->dev, "link%d MAX9271 %sat 0x%x %s\n", idx,
++ sprintf(timeout_str, "retries=%d", priv->timeout - timeout);
++ dev_info(&client->dev, "link%d MAX9271 %sat 0x%x %s %s\n", idx,
+ ret == -EADDRINUSE ? "already " : "", priv->max9271_addr_map[idx],
-+ ret == -ETIMEDOUT ? "not found: timeout GMSL link establish" : "");
++ ret == -ETIMEDOUT ? "not found: timeout GMSL link establish" : "",
++ priv->timeout - timeout? timeout_str : "");
+
+ return ret;
+}
@@ -1176,6 +1239,11 @@ index 0000000..9797d24
+ max9286_max9271_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);
++ }
++
+ ret = max9286_max9271_reverse_channel_setup(client, idx);
+ if (ret)
+ continue;
@@ -1391,6 +1459,7 @@ index 0000000..9797d24
+{
+ struct max9286_max9271_priv *priv;
+ int err, i;
++ char supply_name[10];
+
+ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
@@ -1406,6 +1475,11 @@ index 0000000..9797d24
+ 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 = max9286_max9271_initialize(client);
+ if (err < 0)
+ goto out;
@@ -1428,7 +1502,6 @@ index 0000000..9797d24
+ if (err < 0)
+ goto out;
+ }
-+
+out:
+ return err;
+}
@@ -1475,10 +1548,10 @@ index 0000000..9797d24
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/soc_camera/max9286_max9271.h b/drivers/media/i2c/soc_camera/max9286_max9271.h
new file mode 100644
-index 0000000..0016f28a
+index 0000000..6c2a9e0
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/max9286_max9271.h
-@@ -0,0 +1,243 @@
+@@ -0,0 +1,244 @@
+/*
+ * MAXIM max9286-max9271 GMSL driver include file
+ *
@@ -1504,6 +1577,7 @@ index 0000000..0016f28a
+#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
+
@@ -1724,10 +1798,10 @@ index 0000000..0016f28a
+#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..45169de
+index 0000000..6296647
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/ov10635.c
-@@ -0,0 +1,759 @@
+@@ -0,0 +1,758 @@
+/*
+ * OmniVision ov10635 sensor camera driver
+ *
@@ -1798,7 +1872,7 @@ index 0000000..45169de
+
+ if (priv->max9286_addr) {
+ tmp_addr = client->addr;
-+ client->addr = priv->max9286_addr; /* Deserializer I2C address */
++ 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 */
+ client->addr = tmp_addr;
+ };
@@ -2265,7 +2339,6 @@ index 0000000..45169de
+
+ 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);
+
@@ -2311,7 +2384,7 @@ index 0000000..45169de
+ }
+
+ if (!priv->max9286_addr && !priv->ti964_addr && !priv->ti954_addr) {
-+ dev_err(&client->dev, "deserializer does not present\n");
++ dev_err(&client->dev, "deserializer does not present for OV10635\n");
+ return -EINVAL;
+ }
+
@@ -2489,7 +2562,7 @@ index 0000000..45169de
+#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..66cc490
+index 0000000..a0e510d
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/ov10635.h
@@ -0,0 +1,1139 @@
@@ -3806,10 +3879,10 @@ index 0000000..f2bb706
+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..15acc51
+index 0000000..bee9293
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/ov490_ov10640.c
-@@ -0,0 +1,1046 @@
+@@ -0,0 +1,1064 @@
+/*
+ * OmniVision ov490-ov10640 sensor camera driver
+ *
@@ -4553,10 +4626,28 @@ index 0000000..15acc51
+ reg16_write(client, 0xFFFD, 0x80);
+ reg16_write(client, 0xFFFE, 0x29);
+ usleep_range(100, 150); /* wait 100 us */
-+ timeout = 300;
-+ for (;;) {
++ for (timeout = 300; timeout > 0; timeout--) {
+ reg16_read(client, 0xd000, &val);
-+ if (val == 0x0c || --timeout == 0)
++ 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);
+ }
@@ -4658,7 +4749,7 @@ index 0000000..15acc51
+ }
+
+ if (!priv->max9286_addr && !priv->ti964_addr && !priv->ti954_addr) {
-+ dev_err(&client->dev, "deserializer does not present\n");
++ dev_err(&client->dev, "deserializer does not present for OV490\n");
+ return -EINVAL;
+ }
+
@@ -4858,7 +4949,7 @@ index 0000000..15acc51
+#endif
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..d3290c7
+index 0000000..8c9ecf1
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/ov490_ov10640.h
@@ -0,0 +1,93 @@
@@ -4957,7 +5048,7 @@ index 0000000..d3290c7
+};
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..881615e
+index 0000000..6dc0675
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/ov495_ov2775.c
@@ -0,0 +1,658 @@
@@ -5447,7 +5538,7 @@ index 0000000..881615e
+ }
+
+ if (!priv->ti960_addr && !priv->ti954_addr) {
-+ dev_err(&client->dev, "deserializer does not present\n");
++ dev_err(&client->dev, "deserializer does not present for OV495\n");
+ return -EINVAL;
+ }
+
@@ -5650,10 +5741,10 @@ index 0000000..3f53689
+};
diff --git a/drivers/media/i2c/soc_camera/ti954_ti9x3.c b/drivers/media/i2c/soc_camera/ti954_ti9x3.c
new file mode 100644
-index 0000000..fc7ccda
+index 0000000..1672173
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/ti954_ti9x3.c
-@@ -0,0 +1,417 @@
+@@ -0,0 +1,431 @@
+/*
+ * TI ti954-(ti913/ti953) FPDLinkIII driver
+ *
@@ -5668,9 +5759,10 @@ index 0000000..fc7ccda
+#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 <linux/notifier.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
@@ -5692,6 +5784,7 @@ index 0000000..fc7ccda
+ struct i2c_client *client;
+ int ti9x3_addr_map[4];
+ char chip_id[6];
++ struct regulator *poc_supply[4]; /* PoC power supply */
+ int xtal_gpio;
+};
+
@@ -5824,8 +5917,14 @@ index 0000000..fc7ccda
+
+ ti954_ti9x3_initial_setup(client);
+
-+ for (idx = 0; idx < priv->links; idx++)
++ 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);
++ }
++
+ ti954_ti9x3_fpdlink3_setup(client, idx);
++ }
+
+ client->addr = priv->des_addr;
+
@@ -5992,6 +6091,7 @@ index 0000000..fc7ccda
+{
+ struct ti954_ti9x3_priv *priv;
+ int err, i;
++ char supply_name[10];
+
+ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
@@ -6006,6 +6106,11 @@ index 0000000..fc7ccda
+ 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;
@@ -6073,10 +6178,10 @@ index 0000000..fc7ccda
+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..8dd0f99
+index 0000000..770d306
--- /dev/null
+++ b/drivers/media/i2c/soc_camera/ti964_ti9x3.c
-@@ -0,0 +1,385 @@
+@@ -0,0 +1,399 @@
+/*
+ * TI (ti964/ti960)-(ti913/ti953) FPDLinkIII driver
+ *
@@ -6091,9 +6196,10 @@ index 0000000..8dd0f99
+#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 <linux/notifier.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
@@ -6115,6 +6221,7 @@ index 0000000..8dd0f99
+ struct i2c_client *client;
+ int ti9x3_addr_map[4];
+ char chip_id[6];
++ struct regulator *poc_supply[4]; /* PoC power supply */
+};
+
+static void ti964_ti9x3_read_chipid(struct i2c_client *client)
@@ -6220,8 +6327,14 @@ index 0000000..8dd0f99
+
+ ti964_ti9x3_initial_setup(client);
+
-+ for (idx = 0; idx < priv->links; idx++)
++ 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);
++ }
++
+ ti964_ti9x3_fpdlink3_setup(client, idx);
++ }
+
+ client->addr = priv->des_addr;
+
@@ -6383,6 +6496,7 @@ index 0000000..8dd0f99
+{
+ struct ti964_ti9x3_priv *priv;
+ int err, i;
++ char supply_name[10];
+
+ priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
@@ -6397,6 +6511,11 @@ index 0000000..8dd0f99
+ 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 = ti964_ti9x3_initialize(client);
+ if (err < 0)
+ goto out;