From 805e485b11c5aafacd2ab16a2d699c904ba13372 Mon Sep 17 00:00:00 2001
From: Vladimir Barinov <vladimir.barinov@cogentembedded.com>
Date: Wed, 19 Dec 2018 00:02:17 +0300
Subject: [PATCH 085/122] lvds: AR0233 add different vendor

This adds possibility to setup cameras with different
gpio connection using dts or command line:
ti9x4.gpioX
---
 drivers/media/i2c/soc_camera/ar0233.c  | 36 ++++++++++++++++++----------
 drivers/media/i2c/soc_camera/ov106xx.c | 12 +++++-----
 drivers/media/i2c/soc_camera/ti9x4.c   | 44 +++++++++++++++++++++++++++-------
 3 files changed, 64 insertions(+), 28 deletions(-)

diff --git a/drivers/media/i2c/soc_camera/ar0233.c b/drivers/media/i2c/soc_camera/ar0233.c
index 7c1141c..74ecc85 100644
--- a/drivers/media/i2c/soc_camera/ar0233.c
+++ b/drivers/media/i2c/soc_camera/ar0233.c
@@ -22,7 +22,7 @@
 
 #include "ar0233.h"
 
-#define AR0233_I2C_ADDR		0x10
+static const int ar0233_i2c_addr[] = {0x10, 0x20};
 
 #define AR0233_PID		0x3000
 #define AR0233_VERSION_REG	0x0354
@@ -380,9 +380,23 @@ static int ar0233_initialize(struct i2c_client *client)
 	u16 pid = 0;
 	int ret = 0;
 	int tmp_addr;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ar0233_i2c_addr); i++) {
+		tmp_addr = client->addr;
+		if (priv->ti9x4_addr) {
+			client->addr = priv->ti9x4_addr;/* Deserializer I2C address */
+			reg8_write(client, 0x5d, ar0233_i2c_addr[i] << 1); /* Sensor native I2C address */
+			usleep_range(2000, 2500);	/* wait 2ms */
+		}
+		client->addr = tmp_addr;
 
-	/* check and show model ID */
-	reg16_read16(client, AR0233_PID, &pid);
+		/* check model ID */
+		reg16_read16(client, AR0233_PID, &pid);
+
+		if (pid == AR0233_VERSION_REG)
+			break;
+	}
 
 	if (pid != AR0233_VERSION_REG) {
 		dev_dbg(&client->dev, "Product ID error %x\n", pid);
@@ -395,12 +409,16 @@ static int ar0233_initialize(struct i2c_client *client)
 	if (priv->ti9x4_addr) {
 		/* CLK_OUT=22.5792*160*M/N/CLKDIV -> CLK_OUT=27MHz: CLKDIV=2, M=15, N=251: 22.5792*160/8*15/251=26.987MHz=CLK_OUT */
 		client->addr = priv->ti9x3_addr;			/* Serializer I2C address */
+#if 0
 		reg8_write(client, 0x06, 0x6f);				/* Set CLKDIV and M */
 		reg8_write(client, 0x07, 0xfb);				/* Set N */
-		reg8_write(client, 0x0e, 0x1f);				/* Set FSIN GPIO to output */
+#endif
+		reg8_write(client, 0x0e, 0xf0);				/* Enable all remote gpios */
 	}
 	client->addr = tmp_addr;
 
+	/* Read OTP IDs */
+	ar0233_otp_id_read(client);
 	/* Program wizard registers */
 	ar0233_set_regs(client, ar0233_regs_wizard, ARRAY_SIZE(ar0233_regs_wizard));
 
@@ -409,9 +427,6 @@ static int ar0233_initialize(struct i2c_client *client)
 	val |= (1 << 2);			// Set streamOn bit
 	reg16_write16(client, 0x301a, val);	// Start Streaming
 
-	/* Read OTP IDs */
-	ar0233_otp_id_read(client);
-
 	dev_info(&client->dev, "ar0233 PID %x, res %dx%d, OTP_ID %02x:%02x:%02x:%02x:%02x:%02x\n",
 		 pid, AR0233_MAX_WIDTH, AR0233_MAX_HEIGHT, priv->id[0], priv->id[1], priv->id[2], priv->id[3], priv->id[4], priv->id[5]);
 err:
@@ -444,7 +459,7 @@ static int ar0233_parse_dt(struct device_node *np, struct ar0233_priv *priv)
 	of_node_put(endpoint);
 
 	if (!priv->ti9x4_addr) {
-		dev_err(&client->dev, "deserializer does not present\n");
+		dev_dbg(&client->dev, "deserializer does not present\n");
 		return -EINVAL;
 	}
 
@@ -456,14 +471,9 @@ static int ar0233_parse_dt(struct device_node *np, struct ar0233_priv *priv)
 		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, AR0233_I2C_ADDR << 1);		/* Sensor native I2C address */
-
-		reg8_write(client, 0x6e, 0x8a);				/* GPIO0 - fsin, GPIO1 - NC */
 	}
 	client->addr = tmp_addr;
 
-	mdelay(10);
-
 	return 0;
 }
 
diff --git a/drivers/media/i2c/soc_camera/ov106xx.c b/drivers/media/i2c/soc_camera/ov106xx.c
index d6df193..e5d6b67 100644
--- a/drivers/media/i2c/soc_camera/ov106xx.c
+++ b/drivers/media/i2c/soc_camera/ov106xx.c
@@ -51,6 +51,12 @@ static int ov106xx_probe(struct i2c_client *client,
 	int ret;
 	chip_id = -EINVAL;
 
+	ret = ar0233_probe(client, did);
+	if (!ret) {
+		chip_id = ID_AR0233;
+		goto out;
+	}
+
 	ret = ov10635_probe(client, did);
 	if (!ret) {
 		chip_id = ID_OV10635;
@@ -93,12 +99,6 @@ static int ov106xx_probe(struct i2c_client *client,
 		goto out;
 	}
 
-	ret = ar0233_probe(client, did);
-	if (!ret) {
-		chip_id = ID_AR0233;
-		goto out;
-	}
-
 	ret = ar0323_probe(client, did);
 	if (!ret) {
 		chip_id = ID_AR0323;
diff --git a/drivers/media/i2c/soc_camera/ti9x4.c b/drivers/media/i2c/soc_camera/ti9x4.c
index effcf6c..d03c0f9 100644
--- a/drivers/media/i2c/soc_camera/ti9x4.c
+++ b/drivers/media/i2c/soc_camera/ti9x4.c
@@ -44,6 +44,7 @@ struct ti9x4_priv {
 	int			ser_id;
 	int			vc_map;
 	int			csi_map;
+	int			gpio[4];
 	struct gpio_desc	*pwen; /* chip power en */
 	struct gpio_desc	*poc_gpio[4]; /* PoC power supply */
 	struct v4l2_clk		*ref_clk; /* ref clock */
@@ -81,6 +82,16 @@ static int csi_map = 0;
 module_param(csi_map, int, 0644);
 MODULE_PARM_DESC(csi_map, " CSI TX MAP (default: 0 - forwarding of all links to CSI0)");
 
+static int gpio0 = 0, gpio1 = 0, gpio2 = 0, gpio3 = 0;
+module_param(gpio0, int, 0644);
+MODULE_PARM_DESC(gpio0, "  GPIO0 function select (default: GPIO0 low level)");
+module_param(gpio1, int, 0644);
+MODULE_PARM_DESC(gpio1, "  GPIO1 function select (default: GPIO1 low level)");
+module_param(gpio2, int, 0644);
+MODULE_PARM_DESC(gpio2, "  GPIO2 function select (default: GPIO2 low level)");
+module_param(gpio3, int, 0644);
+MODULE_PARM_DESC(gpio3, "  GPIO3 function select (default: GPIO3 low level)");
+
 #ifdef TI954_SILICON_ERRATA
 static int indirect_write(struct i2c_client *client, unsigned int page, u8 reg, u8 val)
 {
@@ -204,9 +215,6 @@ static void ti9x4_initial_setup(struct i2c_client *client)
 #endif
 }
 
-//#define SENSOR_ID 0x30  // ov10635
-//#define SENSOR_ID 0x24  // ov490
-
 static void ti9x4_fpdlink3_setup(struct i2c_client *client, int idx)
 {
 	struct ti9x4_priv *priv = i2c_get_clientdata(client);
@@ -230,7 +238,7 @@ static void ti9x4_fpdlink3_setup(struct i2c_client *client, int idx)
 	}
 
 	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, 0x5d, 0x30 << 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 (priv->is_coax)
@@ -262,7 +270,8 @@ static void ti9x4_fpdlink3_setup(struct i2c_client *client, int idx)
 	reg8_write(client, 0x70, ((priv->vc_map >> (idx * 4)) << 6) | 0x1e); /* CSI data type: yuv422 8-bit, assign VC */
 	reg8_write(client, 0x71, ((priv->vc_map >> (idx * 4)) << 6) | 0x2c); /* CSI data type: RAW12, 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 */
+	reg8_write(client, 0x6e, 0x88 | (priv->gpio[1] << 4) | priv->gpio[0]); /* Remote GPIO1/GPIO0 setup */
+	reg8_write(client, 0x6f, 0x88 | (priv->gpio[3] << 4) | priv->gpio[2]); /* Remote GPIO3/GPIO2 setup */
 	reg8_write(client, 0x72, priv->vc_map >> (idx * 4));	/* CSI VC MAP */
 }
 
@@ -285,6 +294,10 @@ static int ti9x4_initialize(struct i2c_client *client)
 		ti9x4_fpdlink3_setup(client, idx);
 	}
 
+	/* extra delay to wait imager power up */
+	if (priv->poc_delay)
+		mdelay(350);
+
 	client->addr = priv->des_addr;
 
 	return 0;
@@ -369,7 +382,7 @@ static int ti9x4_parse_dt(struct i2c_client *client)
 	char forwarding_mode_default[20] = "round-robin"; /* round-robin, synchronized */
 	struct property *csi_rate_prop, *dvp_order_prop;
 	u8 val = 0;
-	char poc_name[10];
+	char name[10];
 
 	if (of_property_read_u32(np, "ti,links", &priv->links))
 		priv->links = 4;
@@ -391,8 +404,8 @@ static int ti9x4_parse_dt(struct i2c_client *client)
 	}
 
 	for (i = 0; i < 4; i++) {
-		sprintf(poc_name, "POC%d", i);
-		priv->poc_gpio[i] = devm_gpiod_get_optional(&client->dev, kstrdup(poc_name, GFP_KERNEL), 0);
+		sprintf(name, "POC%d", i);
+		priv->poc_gpio[i] = devm_gpiod_get_optional(&client->dev, kstrdup(name, GFP_KERNEL), 0);
 	}
 
 	reg8_read(client, 0x00, &val);				/* read TI9x4 I2C address */
@@ -429,9 +442,14 @@ static int ti9x4_parse_dt(struct i2c_client *client)
 	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;
+		priv->poc_delay = 10;
 	if (of_property_read_u32(np, "ti,vc-map", &priv->vc_map))
 		priv->vc_map = 0x3210;
+	for (i = 0; i < 4; i++) {
+		sprintf(name, "ti,gpio%d", i);
+		if (of_property_read_u32(np, name, &priv->gpio[i]))
+			priv->gpio[i] = 0;
+	}
 
 	/*
 	 * CSI forwarding of all links is to CSI0 by default.
@@ -469,6 +487,14 @@ static int ti9x4_parse_dt(struct i2c_client *client)
 		priv->vc_map = vc_map;
 	if (csi_map)
 		priv->csi_map = csi_map;
+	if (gpio0)
+		priv->gpio[0] = gpio0;
+	if (gpio1)
+		priv->gpio[1] = gpio1;
+	if (gpio2)
+		priv->gpio[2] = gpio2;
+	if (gpio3)
+		priv->gpio[3] = gpio3;
 
 	for (i = 0; ; i++) {
 		endpoint = of_graph_get_next_endpoint(np, endpoint);
-- 
2.7.4

